https://github.com/akkartik/mu/blob/master/apps/mu.subx
    1 # The Mu computer's level-2 language, also called Mu.
    2 # http://akkartik.name/post/mu-2019-2
    3 #
    4 # To run:
    5 #   $ ./translate_subx init.linux [0-9]*.subx apps/mu.subx
    6 #   $ ./a.elf < prog.mu > prog.elf
    7 
    8 # == Goals
    9 # 1. Be memory safe. It should be impossible to corrupt the heap, or to create
   10 # a bad pointer. (Requires strong type safety.)
   11 # 2. Do as little as possible to achieve goal 1. The translator should be
   12 # implementable in machine code.
   13 #   - minimize impedance mismatch between source language and SubX target
   14 #     (e.g. programmer manages registers manually)
   15 #   - checks over syntax
   16 #     (e.g. programmer's register allocation is checked)
   17 #   - runtime checks to avoid complex static analysis
   18 #     (e.g. array indexing always checks bounds)
   19 
   20 # == Language description
   21 # A program is a sequence of function and type definitions.
   22 #
   23 # Function example:
   24 #   fn foo n: int -> result/eax: int {
   25 #     ...
   26 #   }
   27 #
   28 # Functions consist of a name, optional inputs, optional outputs and a block.
   29 #
   30 # Function inputs and outputs are variables. All variables have a type and
   31 # storage specifier. They can be placed either in memory (on the stack) or in
   32 # one of 6 named registers.
   33 #   eax ecx edx ebx esi edi
   34 # Variables in registers must be primitive 32-bit types.
   35 # Variables not explicitly placed in a register are on the stack.
   36 #
   37 # Function inputs are always passed in memory (on the stack), while outputs
   38 # are always returned in registers.
   39 #
   40 # Blocks mostly consist of statements.
   41 #
   42 # Statements mostly consist of a name, optional inputs and optional outputs.
   43 #
   44 # Statement inputs are variables or literals. Variables need to specify type
   45 # (and storage) the first time they're mentioned but not later.
   46 #
   47 # Statement outputs, like function outputs, must be variables in registers.
   48 #
   49 # Statement names must be either primitives or user-defined functions.
   50 #
   51 # Primitives can write to any register.
   52 # User-defined functions only write to hard-coded registers. Outputs of each
   53 # call must have the same registers as in the function definition.
   54 #
   55 # There are some other statement types:
   56 #   - blocks. Multiple statements surrounded by '{...}' and optionally
   57 #     prefixed with a label name and ':'
   58 #       - {
   59 #           ...
   60 #         }
   61 #       - foo: {
   62 #           ...
   63 #         }
   64 #
   65 #   - variable definitions on the stack. E.g.:
   66 #       - var foo: int
   67 #       - var bar: (array int 3)
   68 #     There's no initializer; variables are automatically initialized.
   69 #     The type of a local variable is either word-length (4 bytes) or starts with 'ref'.
   70 #
   71 #   - variables definitions in a register. E.g.:
   72 #       - var foo/eax: int <- add bar 1
   73 #     The initializer is mandatory and must be a valid instruction that writes
   74 #     a single output to the right register. In practice registers will
   75 #     usually be either initialized by primitives or copied from eax.
   76 #       - var eax: int <- foo bar quux
   77 #         var floo/ecx: int <- copy eax
   78 #
   79 # Still todo:
   80 #   global variables
   81 #   union types
   82 #
   83 # Formal types:
   84 #   A program is a linked list of functions
   85 #   A function contains:
   86 #     name: (handle array byte)
   87 #     inouts: linked list of vars  <-- 'inouts' is more precise than 'inputs'
   88 #       data: (handle var)
   89 #       next: (handle list)
   90 #     outputs: linked list of vars
   91 #       data: (handle var)
   92 #       next: (handle list)
   93 #     body: (handle block)
   94 #   A var-type contains:
   95 #     name: (handle array byte)
   96 #     type: (handle type-tree)
   97 #
   98 #   A statement can be:
   99 #     tag 0: a block
  100 #     tag 1: a simple statement (stmt1)
  101 #     tag 2: a variable defined on the stack
  102 #     tag 3: a variable defined in a register
  103 #
  104 #   A block contains:
  105 #     tag: 0
  106 #     statements: (handle list stmt)
  107 #     name: (handle array byte) -- starting with '$'
  108 #
  109 #   A regular statement contains:
  110 #     tag: 1
  111 #     operation: (handle array byte)
  112 #     inouts: (handle list operand)
  113 #     outputs: (handle list var)
  114 #
  115 #   A variable defined on the stack contains:
  116 #     tag: 2
  117 #     name: (handle array byte)
  118 #     type: (handle type-tree)
  119 #
  120 #   A variable defined in a register contains:
  121 #     tag: 3
  122 #     name: (handle array byte)
  123 #     type: (handle type-tree)
  124 #     reg: (handle array byte)
  125 
  126 # == Translation: managing the stack
  127 # Now that we know what the language looks like in the large, let's think
  128 # about how translation happens from the bottom up. One crucial piece of the
  129 # puzzle is how Mu will clean up variables defined on the stack for you.
  130 #
  131 # Assume that we maintain a 'functions' list while parsing source code. And a
  132 # 'primitives' list is a global constant. Both these contain enough information
  133 # to perform type-checking on function calls or primitive statements, respectively.
  134 #
  135 # Defining variables pushes them on a stack with the current block depth and
  136 # enough information about their location (stack offset or register).
  137 # Starting a block increments the current block id.
  138 # Each statement now has enough information to emit code for it.
  139 # Ending a block is where the magic happens:
  140 #   pop all variables at the current block depth
  141 #   emit code to restore all register variables introduced at the current depth
  142 #   emit code to clean up all stack variables at the current depth (just increment esp)
  143 #   decrement the current block depth
  144 #
  145 # Formal types:
  146 #   live-vars: stack of vars
  147 #   var:
  148 #     name: (handle array byte)
  149 #     type: (handle type-tree)
  150 #     block: int
  151 #     stack-offset: int  (added to ebp)
  152 #     register: (handle array byte)
  153 #       either usual register names
  154 #       or '*' to indicate any register
  155 #   At most one of stack-offset or register-index must be non-zero.
  156 #   A register of '*' designates a variable _template_. Only legal in formal
  157 #   parameters for primitives.
  158 
  159 # == Translating a single function call
  160 # This one's easy. Assuming we've already checked things, we just drop the
  161 # outputs (which use hard-coded registers) and emit inputs in a standard format.
  162 #
  163 # out1, out2, out3, ... <- name inout1, inout2, inout3, ...
  164 # =>
  165 # (name inout1 inout2 inout3)
  166 #
  167 # Formal types:
  168 #   functions: linked list of info
  169 #     name: (handle array byte)
  170 #     inouts: linked list of vars
  171 #     outputs: linked list of vars
  172 #     body: block (linked list of statements)
  173 
  174 # == Translating a single primitive instruction
  175 # A second crucial piece of the puzzle is how Mu converts fairly regular
  176 # primitives with their uniform syntax to SubX instructions with their gnarly
  177 # x86 details.
  178 #
  179 # Mu instructions have inputs and outputs. Primitives can have up to 2 of
  180 # them.
  181 # SubX instructions have rm32 and r32 operands.
  182 # The translation between them covers almost all the possibilities.
  183 #   Instructions with 1 inout may turn into ones with 1 rm32
  184 #     (e.g. incrementing a var on the stack)
  185 #   Instructions with 1 output may turn into ones with 1 rm32
  186 #     (e.g. incrementing a var in a register)
  187 #   1 inout and 1 output may turn into 1 rm32 and 1 r32
  188 #     (e.g. adding a var to a reg)
  189 #   2 inouts may turn into 1 rm32 and 1 r32
  190 #     (e.g. adding a reg to a var)
  191 #   1 inout and 1 literal may turn into 1 rm32 and 1 imm32
  192 #     (e.g. adding a constant to a var)
  193 #   1 output and 1 literal may turn into 1 rm32 and 1 imm32
  194 #     (e.g. adding a constant to a reg)
  195 #   2 outputs to hardcoded registers and 1 inout may turn into 1 rm32
  196 #     (special-case: divide edx:eax by a var or reg)
  197 # Observations:
  198 #   We always emit rm32. It may be the first inout or the first output.
  199 #   We may emit r32 or imm32 or neither.
  200 #   When we emit r32 it may come from first inout or second inout or first output.
  201 #
  202 # Accordingly, the formal data structure for a primitive looks like this:
  203 #   primitives: linked list of info
  204 #     name: (handle array byte)
  205 #     mu-inouts: linked list of vars to check
  206 #     mu-outputs: linked list of vars to check; at most a singleton
  207 #     subx-name: (handle array byte)
  208 #     subx-rm32: enum arg-location
  209 #     subx-r32: enum arg-location
  210 #     subx-imm32: enum arg-location
  211 #     subx-imm8: enum arg-location
  212 #     subx-disp32: enum arg-location
  213 #     output-is-write-only: boolean
  214 #   arg-location: enum
  215 #     0 means none
  216 #     1 means first inout
  217 #     2 means second inout
  218 #     3 means first output
  219 
  220 # == Translating a block
  221 # Emit block name if necessary
  222 # Emit '{'
  223 # When you encounter a statement, emit it as above
  224 # When you encounter a variable declaration
  225 #   emit any code needed for it (bzeros)
  226 #   push it on the var stack
  227 #   update register dict if necessary
  228 # When you encounter '}'
  229 #   While popping variables off the var stack until block id changes
  230 #     Emit code needed to clean up the stack
  231 #       either increment esp
  232 #       or pop into appropriate register
  233 
  234 # The rest is straightforward.
  235 
  236 == data
  237 
  238 Program:
  239 _Program-functions:  # (handle function)
  240   0/imm32
  241 _Program-functions->payload:
  242   0/imm32
  243 _Program-types:  # (handle typeinfo)
  244   0/imm32
  245 _Program-types->payload:
  246   0/imm32
  247 _Program-signatures:  # (handle function)
  248   0/imm32
  249 _Program-signatures->payload:
  250   0/imm32
  251 
  252 # Some constants for simulating the data structures described above.
  253 # Many constants here come with a type in a comment.
  254 #
  255 # Sometimes the type is of the value at that offset for the given type. For
  256 # example, if you start at a function record and move forward Function-inouts
  257 # bytes, you'll find a (handle list var).
  258 #
  259 # At other times, the type is of the constant itself. For example, the type of
  260 # the constant Function-size is (addr int). To get the size of a function,
  261 # look in *Function-size.
  262 
  263 Function-name:  # (handle array byte)
  264   0/imm32
  265 Function-inouts:  # (handle list var)
  266   8/imm32
  267 Function-outputs:  # (handle list var)
  268   0x10/imm32
  269 Function-body:  # (handle block)
  270   0x18/imm32
  271 Function-next:  # (handle function)
  272   0x20/imm32
  273 Function-size:  # (addr int)
  274   0x28/imm32/40
  275 
  276 Primitive-name:  # (handle array byte)
  277   0/imm32
  278 Primitive-inouts:  # (handle list var)
  279   8/imm32
  280 Primitive-outputs:  # (handle list var)
  281   0x10/imm32
  282 Primitive-subx-name:  # (handle array byte)
  283   0x18/imm32
  284 Primitive-subx-rm32:  # enum arg-location
  285   0x20/imm32
  286 Primitive-subx-r32:  # enum arg-location
  287   0x24/imm32
  288 Primitive-subx-imm32:  # enum arg-location
  289   0x28/imm32
  290 Primitive-subx-imm8:  # enum arg-location  -- only for bit shifts
  291   0x2c/imm32
  292 Primitive-subx-disp32:  # enum arg-location  -- only for branches
  293   0x30/imm32
  294 Primitive-output-is-write-only:  # boolean
  295   0x34/imm32
  296 Primitive-next:  # (handle function)
  297   0x38/imm32
  298 Primitive-size:  # (addr int)
  299   0x40/imm32/60
  300 
  301 Stmt-tag:  # int
  302   0/imm32
  303 
  304 Block-stmts:  # (handle list stmt)
  305   4/imm32
  306 Block-var:  # (handle var)
  307   0xc/imm32
  308 
  309 Stmt1-operation:  # (handle array byte)
  310   4/imm32
  311 Stmt1-inouts:  # (handle stmt-var)
  312   0xc/imm32
  313 Stmt1-outputs:  # (handle stmt-var)
  314   0x14/imm32
  315 
  316 Vardef-var:  # (handle var)
  317   4/imm32
  318 
  319 Regvardef-operation:  # (handle array byte)
  320   4/imm32
  321 Regvardef-inouts:  # (handle stmt-var)
  322   0xc/imm32
  323 Regvardef-outputs:  # (handle stmt-var)  # will have exactly one element
  324   0x14/imm32
  325 
  326 Stmt-size:  # (addr int)
  327   0x1c/imm32
  328 
  329 Var-name:  # (handle array byte)
  330   0/imm32
  331 Var-type:  # (handle type-tree)
  332   8/imm32
  333 Var-block-depth:  # int -- not available until code-generation time
  334   0x10/imm32
  335 Var-offset:  # int -- not available until code-generation time
  336   0x14/imm32
  337 Var-register:  # (handle array byte) -- name of a register
  338   0x18/imm32
  339 Var-size:  # (addr int)
  340   0x20/imm32
  341 
  342 List-value:  # (handle _)
  343   0/imm32
  344 List-next:  # (handle list _)
  345   8/imm32
  346 List-size:  # (addr int)
  347   0x10/imm32
  348 
  349 # A stmt-var is like a list of vars with call-site specific metadata
  350 Stmt-var-value:  # (handle var)
  351   0/imm32
  352 Stmt-var-next:  # (handle stmt-var)
  353   8/imm32
  354 Stmt-var-is-deref:  # boolean
  355   0x10/imm32
  356 Stmt-var-size:  # (addr int)
  357   0x14/imm32
  358 
  359 # A live-var is a var augmented with information needed for tracking live
  360 # variables.
  361 Live-var-value:  # (handle var)
  362   0/imm32
  363 Live-var-register-spilled:  # boolean; only used if value is in a register, and only during code-gen
  364   8/imm32
  365 Live-var-size:  # (addr int)
  366   0xc/imm32
  367 
  368 # Types are expressed as trees (s-expressions) of type-ids (ints).
  369 
  370 Type-tree-is-atom:  # boolean
  371   0/imm32
  372 # if is-atom?
  373 Type-tree-value:  # type-id
  374   4/imm32
  375 Type-tree-value-size:  # int (for static data structure sizes)
  376   8/imm32
  377 Type-tree-parameter-name:  # (handle array byte) for type parameters
  378   8/imm32
  379 # unless is-atom?
  380 Type-tree-left:  # (addr type-tree)
  381   4/imm32
  382 Type-tree-right:  # (addr type-tree)
  383   0xc/imm32
  384 #
  385 Type-tree-size:  # (addr int)
  386   0x14/imm32
  387 
  388 # Types
  389 
  390 # TODO: Turn this data structure into valid Mu, with (fake) handles rather than addrs.
  391 Type-id:  # (stream (addr array byte))
  392   0/imm32/write  # initialized later from Primitive-type-ids
  393   0/imm32/read
  394   0x100/imm32/size
  395   # data
  396   "literal"/imm32  # 0: value is just the name
  397   "int"/imm32  # 1
  398   "addr"/imm32  # 2
  399   "array"/imm32  # 3
  400   "handle"/imm32  # 4
  401   "boolean"/imm32  # 5
  402   "constant"/imm32  # 6: like a literal, but value is an int in Var-offset
  403   "offset"/imm32  # 7: (offset T) is guaranteed to be a 32-bit multiple of size-of(T)
  404   # 0x20
  405   "byte"/imm32  # 8
  406   0/imm32  # 9 reserved for array-capacity; value is in Type-tree-size.
  407            # Not to be used directly, so we don't include a name here.
  408   0/imm32  # 10 reserved for type parameters; value is (address array byte) in Type-tree-value2.
  409            # Not to be used directly, so we don't include a name here.
  410   # some SubX types deliberately left undefined in Mu; they can only be operated on using SubX primitives
  411   "stream"/imm32  # 11
  412   "slice"/imm32  # 12
  413   # Keep Primitive-type-ids in sync if you add types here.
  414                                           0/imm32 0/imm32 0/imm32
  415   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  416   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  417   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  418   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  419   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  420   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  421 
  422 Primitive-type-ids:  # (addr int)
  423   0x34
  424 
  425 # == Type definitions
  426 # Program->types contains some typeinfo for each type definition.
  427 # Types contain vars with types, but can't specify registers.
  428 Typeinfo-id:  # type-id
  429   0/imm32
  430 Typeinfo-fields:  # (handle table (handle array byte) (handle typeinfo-entry))
  431   4/imm32
  432 # Total size must be >= 0
  433 # During parsing it may take on two additional values:
  434 #   -2: not yet initialized
  435 #   -1: in process of being computed
  436 # See populate-mu-type-sizes for details.
  437 Typeinfo-total-size-in-bytes:  # int
  438   0xc/imm32
  439 Typeinfo-next:  # (handle typeinfo)
  440   0x10/imm32
  441 Typeinfo-size:  # (addr int)
  442   0x18/imm32
  443 
  444 # Each entry in the typeinfo->fields table has a pointer to a string and a
  445 # pointer to a typeinfo-entry.
  446 Typeinfo-fields-row-size:  # (addr int)
  447   0x10/imm32
  448 
  449 # typeinfo-entry objects have information about a field in a single record type
  450 #
  451 # each field of a type is represented using two var's:
  452 #   1. the input var: expected type of the field; convenient for creating using parse-var-with-type
  453 #   2. the output var: a constant containing the byte offset; convenient for code-generation
  454 # computing the output happens after parsing; in the meantime we preserve the
  455 # order of fields in the 'index' field.
  456 Typeinfo-entry-input-var:  # (handle var)
  457   0/imm32
  458 Typeinfo-entry-index:  # int
  459   8/imm32
  460 Typeinfo-entry-output-var:  # (handle var)
  461   0xc/imm32
  462 Typeinfo-entry-size:  # (addr int)
  463   0x14/imm32
  464 
  465 == code
  466 
  467 Entry:
  468     # . prologue
  469     89/<- %ebp 4/r32/esp
  470     (new-segment *Heap-size Heap)
  471     # if (argv[1] == "test') run-tests()
  472     {
  473       # if (argc <= 1) break
  474       81 7/subop/compare *ebp 1/imm32
  475       7e/jump-if-<= break/disp8
  476       # if (argv[1] != "test") break
  477       (kernel-string-equal? *(ebp+8) "test")  # => eax
  478       3d/compare-eax-and 0/imm32/false
  479       74/jump-if-= break/disp8
  480       #
  481       (run-tests)
  482       # syscall(exit, *Num-test-failures)
  483       8b/-> *Num-test-failures 3/r32/ebx
  484       eb/jump $mu-main:end/disp8
  485     }
  486     # otherwise convert Stdin
  487     (convert-mu Stdin Stdout Stderr 0)
  488     (flush Stdout)
  489     # syscall(exit, 0)
  490     bb/copy-to-ebx 0/imm32
  491 $mu-main:end:
  492     e8/call syscall_exit/disp32
  493 
  494 convert-mu:  # in: (addr buffered-file), out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
  495     # . prologue
  496     55/push-ebp
  497     89/<- %ebp 4/r32/esp
  498     # . save registers
  499     50/push-eax
  500     # initialize global data structures
  501     c7 0/subop/copy *Next-block-index 1/imm32
  502     8b/-> *Primitive-type-ids 0/r32/eax
  503     89/<- *Type-id 0/r32/eax  # stream-write
  504     c7 0/subop/copy *_Program-functions 0/imm32
  505     c7 0/subop/copy *_Program-functions->payload 0/imm32
  506     c7 0/subop/copy *_Program-types 0/imm32
  507     c7 0/subop/copy *_Program-types->payload 0/imm32
  508     c7 0/subop/copy *_Program-signatures 0/imm32
  509     c7 0/subop/copy *_Program-signatures->payload 0/imm32
  510     #
  511     (parse-mu *(ebp+8) *(ebp+0x10) *(ebp+0x14))
  512     (populate-mu-type-sizes *(ebp+0x10) *(ebp+0x14))
  513 #?     (dump-typeinfos "=== typeinfos\n")
  514     (check-mu-types *(ebp+0x10) *(ebp+0x14))
  515     (emit-subx *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
  516 $convert-mu:end:
  517     # . restore registers
  518     58/pop-to-eax
  519     # . epilogue
  520     89/<- %esp 5/r32/ebp
  521     5d/pop-to-ebp
  522     c3/return
  523 
  524 test-convert-empty-input:
  525     # empty input => empty output
  526     # . prologue
  527     55/push-ebp
  528     89/<- %ebp 4/r32/esp
  529     # setup
  530     (clear-stream _test-input-stream)
  531     (clear-stream $_test-input-buffered-file->buffer)
  532     (clear-stream _test-output-stream)
  533     (clear-stream $_test-output-buffered-file->buffer)
  534     #
  535     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  536     (flush _test-output-buffered-file)
  537     (check-stream-equal _test-output-stream "" "F - test-convert-empty-input")
  538     # . epilogue
  539     89/<- %esp 5/r32/ebp
  540     5d/pop-to-ebp
  541     c3/return
  542 
  543 test-convert-function-skeleton:
  544     # . prologue
  545     55/push-ebp
  546     89/<- %ebp 4/r32/esp
  547     # setup
  548     (clear-stream _test-input-stream)
  549     (clear-stream $_test-input-buffered-file->buffer)
  550     (clear-stream _test-output-stream)
  551     (clear-stream $_test-output-buffered-file->buffer)
  552     #
  553     (write _test-input-stream "fn foo {\n")
  554     (write _test-input-stream "}\n")
  555     # convert
  556     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  557     (flush _test-output-buffered-file)
  558 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  564     # check output
  565     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-skeleton/0")
  566     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-skeleton/1")
  567     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-skeleton/2")
  568     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-skeleton/3")
  569     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-skeleton/4")
  570     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-skeleton/5")
  571     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-skeleton/6")
  572     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-skeleton/7")
  573     # . epilogue
  574     89/<- %esp 5/r32/ebp
  575     5d/pop-to-ebp
  576     c3/return
  577 
  578 test-convert-multiple-function-skeletons:
  579     # . prologue
  580     55/push-ebp
  581     89/<- %ebp 4/r32/esp
  582     # setup
  583     (clear-stream _test-input-stream)
  584     (clear-stream $_test-input-buffered-file->buffer)
  585     (clear-stream _test-output-stream)
  586     (clear-stream $_test-output-buffered-file->buffer)
  587     #
  588     (write _test-input-stream "fn foo {\n")
  589     (write _test-input-stream "}\n")
  590     (write _test-input-stream "fn bar {\n")
  591     (write _test-input-stream "}\n")
  592     # convert
  593     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  594     (flush _test-output-buffered-file)
  595 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  601     # check first function
  602     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-multiple-function-skeletons/0")
  603     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/1")
  604     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/2")
  605     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/3")
  606     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/4")
  607     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/5")
  608     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/6")
  609     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/7")
  610     # check second function
  611     (check-next-stream-line-equal _test-output-stream "bar:"                    "F - test-convert-multiple-function-skeletons/10")
  612     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/11")
  613     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/12")
  614     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/13")
  615     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/14")
  616     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/15")
  617     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/16")
  618     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/17")
  619     # . epilogue
  620     89/<- %esp 5/r32/ebp
  621     5d/pop-to-ebp
  622     c3/return
  623 
  624 test-convert-function-with-arg:
  625     # . prologue
  626     55/push-ebp
  627     89/<- %ebp 4/r32/esp
  628     # setup
  629     (clear-stream _test-input-stream)
  630     (clear-stream $_test-input-buffered-file->buffer)
  631     (clear-stream _test-output-stream)
  632     (clear-stream $_test-output-buffered-file->buffer)
  633     #
  634     (write _test-input-stream "fn foo n: int {\n")
  635     (write _test-input-stream "}\n")
  636     # convert
  637     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  638     (flush _test-output-buffered-file)
  639 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  645     # check output
  646     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg/0")
  647     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg/1")
  648     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg/2")
  649     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg/3")
  650     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg/4")
  651     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg/5")
  652     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg/6")
  653     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg/7")
  654     # . epilogue
  655     89/<- %esp 5/r32/ebp
  656     5d/pop-to-ebp
  657     c3/return
  658 
  659 test-convert-function-with-arg-and-body:
  660     # . prologue
  661     55/push-ebp
  662     89/<- %ebp 4/r32/esp
  663     # setup
  664     (clear-stream _test-input-stream)
  665     (clear-stream $_test-input-buffered-file->buffer)
  666     (clear-stream _test-output-stream)
  667     (clear-stream $_test-output-buffered-file->buffer)
  668     #
  669     (write _test-input-stream "fn foo n: int {\n")
  670     (write _test-input-stream "  increment n\n")
  671     (write _test-input-stream "}\n")
  672     # convert
  673     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  674     (flush _test-output-buffered-file)
  675 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  681     # check output
  682     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg-and-body/0")
  683     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg-and-body/1")
  684     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg-and-body/2")
  685     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg-and-body/3")
  686     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-arg-and-body/4")
  687     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-arg-and-body/5")
  688     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-arg-and-body/6")
  689     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-arg-and-body/7")
  690     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-arg-and-body/8")
  691     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg-and-body/9")
  692     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg-and-body/10")
  693     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg-and-body/11")
  694     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg-and-body/12")
  695     # . epilogue
  696     89/<- %esp 5/r32/ebp
  697     5d/pop-to-ebp
  698     c3/return
  699 
  700 test-convert-function-distinguishes-args:
  701     # . prologue
  702     55/push-ebp
  703     89/<- %ebp 4/r32/esp
  704     # setup
  705     (clear-stream _test-input-stream)
  706     (clear-stream $_test-input-buffered-file->buffer)
  707     (clear-stream _test-output-stream)
  708     (clear-stream $_test-output-buffered-file->buffer)
  709     #
  710     (write _test-input-stream "fn foo a: int, b: int {\n")
  711     (write _test-input-stream "  increment b\n")
  712     (write _test-input-stream "}\n")
  713     # convert
  714     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  715     (flush _test-output-buffered-file)
  716 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  722     # check output
  723     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-distinguishes-args/0")
  724     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-distinguishes-args/1")
  725     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-distinguishes-args/2")
  726     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-distinguishes-args/3")
  727     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-distinguishes-args/4")
  728     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-distinguishes-args/5")
  729     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x0000000c)"  "F - test-convert-function-distinguishes-args/6")
  730     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-distinguishes-args/7")
  731     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-distinguishes-args/8")
  732     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-distinguishes-args/9")
  733     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-distinguishes-args/10")
  734     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-distinguishes-args/11")
  735     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-distinguishes-args/12")
  736     # . epilogue
  737     89/<- %esp 5/r32/ebp
  738     5d/pop-to-ebp
  739     c3/return
  740 
  741 test-convert-function-returns-result:
  742     # . prologue
  743     55/push-ebp
  744     89/<- %ebp 4/r32/esp
  745     # setup
  746     (clear-stream _test-input-stream)
  747     (clear-stream $_test-input-buffered-file->buffer)
  748     (clear-stream _test-output-stream)
  749     (clear-stream $_test-output-buffered-file->buffer)
  750     #
  751     (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n")
  752     (write _test-input-stream "  result <- copy a\n")
  753     (write _test-input-stream "  result <- increment\n")
  754     (write _test-input-stream "}\n")
  755     # convert
  756     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  757     (flush _test-output-buffered-file)
  758 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  764     # check output
  765     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-returns-result/0")
  766     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-returns-result/1")
  767     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-returns-result/2")
  768     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-returns-result/3")
  769     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-returns-result/4")
  770     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-returns-result/5")
  771     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-returns-result/6")
  772     (check-next-stream-line-equal _test-output-stream "    40/increment-eax"    "F - test-convert-function-returns-result/7")
  773     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-returns-result/8")
  774     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-returns-result/9")
  775     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-returns-result/10")
  776     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-returns-result/11")
  777     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-returns-result/12")
  778     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-returns-result/13")
  779     # . epilogue
  780     89/<- %esp 5/r32/ebp
  781     5d/pop-to-ebp
  782     c3/return
  783 
  784 test-convert-function-with-literal-arg:
  785     # . prologue
  786     55/push-ebp
  787     89/<- %ebp 4/r32/esp
  788     # setup
  789     (clear-stream _test-input-stream)
  790     (clear-stream $_test-input-buffered-file->buffer)
  791     (clear-stream _test-output-stream)
  792     (clear-stream $_test-output-buffered-file->buffer)
  793     #
  794     (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n")
  795     (write _test-input-stream "  result <- copy a\n")
  796     (write _test-input-stream "  result <- add 1\n")
  797     (write _test-input-stream "}\n")
  798     # convert
  799     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  800     (flush _test-output-buffered-file)
  801 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  807     # check output
  808     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg/0")
  809     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg/1")
  810     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg/2")
  811     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg/3")
  812     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg/4")
  813     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg/5")
  814     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-with-literal-arg/6")
  815     (check-next-stream-line-equal _test-output-stream "    05/add-to-eax 1/imm32"  "F - test-convert-function-with-literal-arg/7")
  816     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg/8")
  817     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg/9")
  818     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg/10")
  819     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg/11")
  820     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg/12")
  821     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg/13")
  822     # . epilogue
  823     89/<- %esp 5/r32/ebp
  824     5d/pop-to-ebp
  825     c3/return
  826 
  827 test-convert-function-with-literal-arg-2:
  828     # . prologue
  829     55/push-ebp
  830     89/<- %ebp 4/r32/esp
  831     # setup
  832     (clear-stream _test-input-stream)
  833     (clear-stream $_test-input-buffered-file->buffer)
  834     (clear-stream _test-output-stream)
  835     (clear-stream $_test-output-buffered-file->buffer)
  836     #
  837     (write _test-input-stream "fn foo a: int, b: int -> result/ebx: int {\n")
  838     (write _test-input-stream "  result <- copy a\n")
  839     (write _test-input-stream "  result <- add 1\n")
  840     (write _test-input-stream "}\n")
  841     # convert
  842     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  843     (flush _test-output-buffered-file)
  844 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  850     # check output
  851     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg-2/0")
  852     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg-2/1")
  853     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg-2/2")
  854     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg-2/3")
  855     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg-2/4")
  856     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg-2/5")
  857     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-with-literal-arg-2/6")
  858     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %ebx 1/imm32"  "F - test-convert-function-with-literal-arg-2/7")
  859     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg-2/8")
  860     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg-2/9")
  861     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg-2/10")
  862     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg-2/11")
  863     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg-2/12")
  864     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg-2/13")
  865     # . epilogue
  866     89/<- %esp 5/r32/ebp
  867     5d/pop-to-ebp
  868     c3/return
  869 
  870 test-convert-function-call-with-literal-arg:
  871     # . prologue
  872     55/push-ebp
  873     89/<- %ebp 4/r32/esp
  874     # setup
  875     (clear-stream _test-input-stream)
  876     (clear-stream $_test-input-buffered-file->buffer)
  877     (clear-stream _test-output-stream)
  878     (clear-stream $_test-output-buffered-file->buffer)
  879     #
  880     (write _test-input-stream "fn main -> result/ebx: int {\n")
  881     (write _test-input-stream "  result <- do-add 3 4\n")
  882     (write _test-input-stream "}\n")
  883     (write _test-input-stream "fn do-add a: int, b: int -> result/ebx: int {\n")
  884     (write _test-input-stream "  result <- copy a\n")
  885     (write _test-input-stream "  result <- add b\n")
  886     (write _test-input-stream "}\n")
  887     # convert
  888     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  889     (flush _test-output-buffered-file)
  890 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  896     # check output
  897     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call-with-literal-arg/0")
  898     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/1")
  899     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/2")
  900     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/3")
  901     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/4")
  902     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call-with-literal-arg/5")
  903     (check-next-stream-line-equal _test-output-stream "    (do-add 3 4)"        "F - test-convert-function-call-with-literal-arg/6")
  904     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/7")
  905     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-literal-arg/8")
  906     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/9")
  907     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/10")
  908     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/11")
  909     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/12")
  910     (check-next-stream-line-equal _test-output-stream "do-add:"                 "F - test-convert-function-call-with-literal-arg/13")
  911     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/14")
  912     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/15")
  913     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/16")
  914     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/17")
  915     (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:loop:"  "F - test-convert-function-call-with-literal-arg/18")
  916     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-call-with-literal-arg/19")
  917     (check-next-stream-line-equal _test-output-stream "    03/add *(ebp+0x0000000c) 0x00000003/r32"  "F - test-convert-function-call-with-literal-arg/20")
  918     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/21")
  919     (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:break:"  "F - test-convert-function-call-with-literal-arg/22")
  920     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/23")
  921     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/24")
  922     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/25")
  923     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/26")
  924     # . epilogue
  925     89/<- %esp 5/r32/ebp
  926     5d/pop-to-ebp
  927     c3/return
  928 
  929 test-convert-function-call-with-signature:
  930     # . prologue
  931     55/push-ebp
  932     89/<- %ebp 4/r32/esp
  933     # setup
  934     (clear-stream _test-input-stream)
  935     (clear-stream $_test-input-buffered-file->buffer)
  936     (clear-stream _test-output-stream)
  937     (clear-stream $_test-output-buffered-file->buffer)
  938     #
  939     (write _test-input-stream "fn main -> result/ebx: int {\n")
  940     (write _test-input-stream "  result <- do-add 3 4\n")
  941     (write _test-input-stream "}\n")
  942     (write _test-input-stream "sig do-add a: int, b: int -> result/ebx: int\n")
  943     # convert
  944     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  945     (flush _test-output-buffered-file)
  946 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  952     # check output
  953     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call-with-signature/0")
  954     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-signature/1")
  955     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-signature/2")
  956     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-signature/3")
  957     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-signature/4")
  958     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call-with-signature/5")
  959     (check-next-stream-line-equal _test-output-stream "    (do-add 3 4)"        "F - test-convert-function-call-with-signature/6")
  960     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-signature/7")
  961     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-signature/8")
  962     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-signature/9")
  963     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-signature/10")
  964     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-signature/11")
  965     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-signature/12")
  966     # . epilogue
  967     89/<- %esp 5/r32/ebp
  968     5d/pop-to-ebp
  969     c3/return
  970 
  971 test-convert-function-with-local-var-in-mem:
  972     # . prologue
  973     55/push-ebp
  974     89/<- %ebp 4/r32/esp
  975     # setup
  976     (clear-stream _test-input-stream)
  977     (clear-stream $_test-input-buffered-file->buffer)
  978     (clear-stream _test-output-stream)
  979     (clear-stream $_test-output-buffered-file->buffer)
  980     #
  981     (write _test-input-stream "fn foo {\n")
  982     (write _test-input-stream "  var x: int\n")
  983     (write _test-input-stream "  increment x\n")
  984     (write _test-input-stream "}\n")
  985     # convert
  986     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  987     (flush _test-output-buffered-file)
  988 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  994     # check output
  995     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-mem/0")
  996     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-mem/1")
  997     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-mem/2")
  998     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-mem/3")
  999     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-mem/4")
 1000     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-mem/5")
 1001     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-in-mem/6")
 1002     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-mem/7")
 1003     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-local-var-in-mem/8")
 1004     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-mem/9")
 1005     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-mem/10")
 1006     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-mem/11")
 1007     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-mem/12")
 1008     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-mem/13")
 1009     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-mem/14")
 1010     # . epilogue
 1011     89/<- %esp 5/r32/ebp
 1012     5d/pop-to-ebp
 1013     c3/return
 1014 
 1015 test-convert-invalid-literal:
 1016     # . prologue
 1017     55/push-ebp
 1018     89/<- %ebp 4/r32/esp
 1019     # setup
 1020     (clear-stream _test-input-stream)
 1021     (clear-stream $_test-input-buffered-file->buffer)
 1022     (clear-stream _test-output-stream)
 1023     (clear-stream $_test-output-buffered-file->buffer)
 1024     (clear-stream _test-error-stream)
 1025     (clear-stream $_test-error-buffered-file->buffer)
 1026     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1027     68/push 0/imm32
 1028     68/push 0/imm32
 1029     89/<- %edx 4/r32/esp
 1030     (tailor-exit-descriptor %edx 0x10)
 1031     #
 1032     (write _test-input-stream "fn foo {\n")
 1033     (write _test-input-stream "  increment 1n\n")
 1034     (write _test-input-stream "}\n")
 1035     # convert
 1036     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1037     # registers except esp clobbered at this point
 1038     # restore ed
 1039     89/<- %edx 4/r32/esp
 1040     (flush _test-output-buffered-file)
 1041     (flush _test-error-buffered-file)
 1042 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1048     # check output
 1049     (check-stream-equal _test-output-stream  ""  "F - test-convert-invalid-literal: output should be empty")
 1050     (check-next-stream-line-equal _test-error-stream  "fn foo: variable '1n' cannot begin with a digit (or do you have a typo in a number?)"  "F - test-convert-invalid-literal: error message")
 1051     # check that stop(1) was called
 1052     (check-ints-equal *(edx+4) 2 "F - test-convert-invalid-literal: exit status")
 1053     # don't restore from ebp
 1054     81 0/subop/add %esp 8/imm32
 1055     # . epilogue
 1056     5d/pop-to-ebp
 1057     c3/return
 1058 
 1059 test-local-var-in-mem-has-no-initializer:
 1060     # . prologue
 1061     55/push-ebp
 1062     89/<- %ebp 4/r32/esp
 1063     # setup
 1064     (clear-stream _test-input-stream)
 1065     (clear-stream $_test-input-buffered-file->buffer)
 1066     (clear-stream _test-output-stream)
 1067     (clear-stream $_test-output-buffered-file->buffer)
 1068     (clear-stream _test-error-stream)
 1069     (clear-stream $_test-error-buffered-file->buffer)
 1070     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1071     68/push 0/imm32
 1072     68/push 0/imm32
 1073     89/<- %edx 4/r32/esp
 1074     (tailor-exit-descriptor %edx 0x10)
 1075     #
 1076     (write _test-input-stream "fn foo {\n")
 1077     (write _test-input-stream "  var x: int <- copy 0\n")
 1078     (write _test-input-stream "  increment x\n")
 1079     (write _test-input-stream "}\n")
 1080     # convert
 1081     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1082     # registers except esp clobbered at this point
 1083     # restore ed
 1084     89/<- %edx 4/r32/esp
 1085     (flush _test-output-buffered-file)
 1086     (flush _test-error-buffered-file)
 1087 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1093     # check output
 1094     (check-stream-equal _test-output-stream  ""  "F - test-var-in-mem-has-no-initializer: output should be empty")
 1095     (check-next-stream-line-equal _test-error-stream  "fn foo: var x: variables on the stack can't take an initializer"  "F - test-var-in-mem-has-no-initializer: error message")
 1096     # check that stop(1) was called
 1097     (check-ints-equal *(edx+4) 2 "F - test-var-in-mem-has-no-initializer: exit status")
 1098     # don't restore from ebp
 1099     81 0/subop/add %esp 8/imm32
 1100     # . epilogue
 1101     5d/pop-to-ebp
 1102     c3/return
 1103 
 1104 test-convert-function-with-local-var-with-compound-type-in-mem:
 1105     # . prologue
 1106     55/push-ebp
 1107     89/<- %ebp 4/r32/esp
 1108     # setup
 1109     (clear-stream _test-input-stream)
 1110     (clear-stream $_test-input-buffered-file->buffer)
 1111     (clear-stream _test-output-stream)
 1112     (clear-stream $_test-output-buffered-file->buffer)
 1113     #
 1114     (write _test-input-stream "fn foo {\n")
 1115     (write _test-input-stream "  var x: (addr int)\n")
 1116     (write _test-input-stream "  copy-to x, 0\n")
 1117     (write _test-input-stream "}\n")
 1118     # convert
 1119     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1120     (flush _test-output-buffered-file)
 1121 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1127     # check output
 1128     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-compound-type-in-mem/0")
 1129     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/1")
 1130     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-compound-type-in-mem/2")
 1131     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/3")
 1132     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/4")
 1133     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-compound-type-in-mem/5")
 1134     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-compound-type-in-mem/6")
 1135     (check-next-stream-line-equal _test-output-stream "    c7 0/subop/copy *(ebp+0xfffffffc) 0/imm32"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/7")
 1136     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/8")
 1137     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/9")
 1138     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/10")
 1139     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/11")
 1140     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/12")
 1141     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-with-compound-type-in-mem/13")
 1142     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-compound-type-in-mem/14")
 1143     # . epilogue
 1144     89/<- %esp 5/r32/ebp
 1145     5d/pop-to-ebp
 1146     c3/return
 1147 
 1148 test-convert-function-with-local-var-in-reg:
 1149     # . prologue
 1150     55/push-ebp
 1151     89/<- %ebp 4/r32/esp
 1152     # setup
 1153     (clear-stream _test-input-stream)
 1154     (clear-stream $_test-input-buffered-file->buffer)
 1155     (clear-stream _test-output-stream)
 1156     (clear-stream $_test-output-buffered-file->buffer)
 1157     #
 1158     (write _test-input-stream "fn foo {\n")
 1159     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1160     (write _test-input-stream "  x <- increment\n")
 1161     (write _test-input-stream "}\n")
 1162     # convert
 1163     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1164     (flush _test-output-buffered-file)
 1165 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1171     # check output
 1172     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-reg/0")
 1173     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-reg/1")
 1174     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-reg/2")
 1175     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-reg/3")
 1176     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-reg/4")
 1177     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-reg/5")
 1178     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-in-reg/6")
 1179     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-convert-function-with-local-var-in-reg/7")
 1180     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-local-var-in-reg/8")
 1181     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-in-reg/9")
 1182     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-reg/10")
 1183     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-reg/11")
 1184     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-reg/12")
 1185     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-reg/13")
 1186     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-reg/14")
 1187     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-reg/15")
 1188     # . epilogue
 1189     89/<- %esp 5/r32/ebp
 1190     5d/pop-to-ebp
 1191     c3/return
 1192 
 1193 test-convert-function-with-allocate:
 1194     # . prologue
 1195     55/push-ebp
 1196     89/<- %ebp 4/r32/esp
 1197     # setup
 1198     (clear-stream _test-input-stream)
 1199     (clear-stream $_test-input-buffered-file->buffer)
 1200     (clear-stream _test-output-stream)
 1201     (clear-stream $_test-output-buffered-file->buffer)
 1202     #
 1203     (write _test-input-stream "fn foo {\n")
 1204     (write _test-input-stream "  var x/ecx: (addr handle int) <- copy 0\n")
 1205     (write _test-input-stream "  allocate x\n")
 1206     (write _test-input-stream "}\n")
 1207     # convert
 1208     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1209     (flush _test-output-buffered-file)
 1210 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1216     # check output
 1217     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-allocate/0")
 1218     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-allocate/1")
 1219     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-allocate/2")
 1220     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-allocate/3")
 1221     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-allocate/4")
 1222     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-allocate/5")
 1223     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-allocate/6")
 1224     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-allocate/7")
 1225     (check-next-stream-line-equal _test-output-stream "    (allocate Heap 0x00000004 %ecx)"  "F - test-convert-function-with-allocate/8")  # 4 = size-of(int)
 1226     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-allocate/9")
 1227     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-allocate/10")
 1228     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-allocate/11")
 1229     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-allocate/12")
 1230     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-allocate/13")
 1231     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-allocate/14")
 1232     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-allocate/15")
 1233     # . epilogue
 1234     89/<- %esp 5/r32/ebp
 1235     5d/pop-to-ebp
 1236     c3/return
 1237 
 1238 test-initializer-in-hex:
 1239     # . prologue
 1240     55/push-ebp
 1241     89/<- %ebp 4/r32/esp
 1242     # setup
 1243     (clear-stream _test-input-stream)
 1244     (clear-stream $_test-input-buffered-file->buffer)
 1245     (clear-stream _test-output-stream)
 1246     (clear-stream $_test-output-buffered-file->buffer)
 1247     (clear-stream _test-error-stream)
 1248     (clear-stream $_test-error-buffered-file->buffer)
 1249     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1250     68/push 0/imm32
 1251     68/push 0/imm32
 1252     89/<- %edx 4/r32/esp
 1253     (tailor-exit-descriptor %edx 0x10)
 1254     #
 1255     (write _test-input-stream "fn foo {\n")
 1256     (write _test-input-stream "  var x/ecx: int <- copy 10\n")
 1257     (write _test-input-stream "}\n")
 1258     # convert
 1259     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1260     # registers except esp clobbered at this point
 1261     # restore ed
 1262     89/<- %edx 4/r32/esp
 1263     (flush _test-output-buffered-file)
 1264     (flush _test-error-buffered-file)
 1265 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1271     # check output
 1272     (check-stream-equal _test-output-stream  ""  "F - test-initializer-in-hex: output should be empty")
 1273     (check-next-stream-line-equal _test-error-stream  "literal integers are always hex in Mu; either start '10' with a '0x' to be unambiguous, or convert it to decimal."  "F - test-initializer-in-hex: error message")
 1274     # check that stop(1) was called
 1275     (check-ints-equal *(edx+4) 2 "F - test-initializer-in-hex: exit status")
 1276     # don't restore from ebp
 1277     81 0/subop/add %esp 8/imm32
 1278     # . epilogue
 1279     5d/pop-to-ebp
 1280     c3/return
 1281 
 1282 test-convert-function-with-second-local-var-in-same-reg:
 1283     # . prologue
 1284     55/push-ebp
 1285     89/<- %ebp 4/r32/esp
 1286     # setup
 1287     (clear-stream _test-input-stream)
 1288     (clear-stream $_test-input-buffered-file->buffer)
 1289     (clear-stream _test-output-stream)
 1290     (clear-stream $_test-output-buffered-file->buffer)
 1291     #
 1292     (write _test-input-stream "fn foo {\n")
 1293     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1294     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1295     (write _test-input-stream "  y <- increment\n")
 1296     (write _test-input-stream "}\n")
 1297     # convert
 1298     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1299     (flush _test-output-buffered-file)
 1300 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1306     # check output
 1307     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-second-local-var-in-same-reg/0")
 1308     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-second-local-var-in-same-reg/1")
 1309     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-second-local-var-in-same-reg/2")
 1310     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-second-local-var-in-same-reg/3")
 1311     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-second-local-var-in-same-reg/4")
 1312     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-second-local-var-in-same-reg/5")
 1313     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-second-local-var-in-same-reg/6")
 1314     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-convert-function-with-second-local-var-in-same-reg/7")
 1315     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-convert-function-with-second-local-var-in-same-reg/8")
 1316     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-second-local-var-in-same-reg/9")
 1317     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-second-local-var-in-same-reg/10")
 1318     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-second-local-var-in-same-reg/11")
 1319     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-second-local-var-in-same-reg/12")
 1320     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-second-local-var-in-same-reg/13")
 1321     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-second-local-var-in-same-reg/14")
 1322     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-second-local-var-in-same-reg/15")
 1323     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-second-local-var-in-same-reg/16")
 1324     # . epilogue
 1325     89/<- %esp 5/r32/ebp
 1326     5d/pop-to-ebp
 1327     c3/return
 1328 
 1329 test-read-clobbered-reg-var:
 1330     # . prologue
 1331     55/push-ebp
 1332     89/<- %ebp 4/r32/esp
 1333     # setup
 1334     (clear-stream _test-input-stream)
 1335     (clear-stream $_test-input-buffered-file->buffer)
 1336     (clear-stream _test-output-stream)
 1337     (clear-stream $_test-output-buffered-file->buffer)
 1338     (clear-stream _test-error-stream)
 1339     (clear-stream $_test-error-buffered-file->buffer)
 1340     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)  # bytes of args in call to convert-mu
 1341     68/push 0/imm32
 1342     68/push 0/imm32
 1343     89/<- %edx 4/r32/esp
 1344     (tailor-exit-descriptor %edx 0x10)
 1345     #
 1346     (write _test-input-stream "fn foo {\n")
 1347     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1348     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1349     (write _test-input-stream "  x <- increment\n")
 1350     (write _test-input-stream "}\n")
 1351     # convert
 1352     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1353     # registers except esp clobbered at this point
 1354     # restore ed
 1355     89/<- %edx 4/r32/esp
 1356     (flush _test-output-buffered-file)
 1357     (flush _test-error-buffered-file)
 1358 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1364     # check output
 1365     (check-stream-equal _test-output-stream  ""  "F - test-read-clobbered-reg-var: output should be empty")
 1366     (check-next-stream-line-equal _test-error-stream  "fn foo: register ecx reads var 'x' after writing var 'y'"  "F - test-read-clobbered-reg-var: error message")
 1367     # check that stop(1) was called
 1368     (check-ints-equal *(edx+4) 2 "F - test-read-clobbered-reg-var: exit status")
 1369     # don't restore from ebp
 1370     81 0/subop/add %esp 8/imm32
 1371     # . epilogue
 1372     5d/pop-to-ebp
 1373     c3/return
 1374 
 1375 test-convert-function-call:
 1376     # . prologue
 1377     55/push-ebp
 1378     89/<- %ebp 4/r32/esp
 1379     # setup
 1380     (clear-stream _test-input-stream)
 1381     (clear-stream $_test-input-buffered-file->buffer)
 1382     (clear-stream _test-output-stream)
 1383     (clear-stream $_test-output-buffered-file->buffer)
 1384     #
 1385     (write _test-input-stream "fn main -> result/ebx: int {\n")
 1386     (write _test-input-stream "  result <- foo\n")
 1387     (write _test-input-stream "}\n")
 1388     (write _test-input-stream "fn foo -> result/ebx: int {\n")
 1389     (write _test-input-stream "  result <- copy 3\n")
 1390     (write _test-input-stream "}\n")
 1391     # convert
 1392     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1393     (flush _test-output-buffered-file)
 1394 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1400     # check output
 1401     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call/0")
 1402     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call/1")
 1403     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call/2")
 1404     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call/3")
 1405     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call/4")
 1406     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call/5")
 1407     (check-next-stream-line-equal _test-output-stream "    (foo)"               "F - test-convert-function-call/6")
 1408     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call/7")
 1409     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call/8")
 1410     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call/9")
 1411     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call/10")
 1412     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call/11")
 1413     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call/12")
 1414     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call/13")
 1415     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call/14")
 1416     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call/15")
 1417     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call/16")
 1418     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call/17")
 1419     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"  "F - test-convert-function-call/18")
 1420     (check-next-stream-line-equal _test-output-stream "    bb/copy-to-ebx 3/imm32"  "F - test-convert-function-call/19")
 1421     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call/20")
 1422     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-call/21")
 1423     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call/22")
 1424     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call/23")
 1425     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call/24")
 1426     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call/25")
 1427     # . epilogue
 1428     89/<- %esp 5/r32/ebp
 1429     5d/pop-to-ebp
 1430     c3/return
 1431 
 1432 test-convert-function-call-with-inout-with-compound-type:
 1433     # . prologue
 1434     55/push-ebp
 1435     89/<- %ebp 4/r32/esp
 1436     # setup
 1437     (clear-stream _test-input-stream)
 1438     (clear-stream $_test-input-buffered-file->buffer)
 1439     (clear-stream _test-output-stream)
 1440     (clear-stream $_test-output-buffered-file->buffer)
 1441     #
 1442     (write _test-input-stream "fn f {\n")
 1443     (write _test-input-stream "  var x: (addr int)\n")
 1444     (write _test-input-stream "  g x\n")
 1445     (write _test-input-stream "}\n")
 1446     (write _test-input-stream "fn g a: (addr int) {\n")
 1447     (write _test-input-stream "}\n")
 1448     # convert
 1449     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1450     (flush _test-output-buffered-file)
 1451 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1457     # check output
 1458     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-inout-with-compound-type/0")
 1459     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-inout-with-compound-type/1")
 1460     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-inout-with-compound-type/2")
 1461     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-inout-with-compound-type/3")
 1462     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-inout-with-compound-type/4")
 1463     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-inout-with-compound-type/5")
 1464     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-inout-with-compound-type/6")
 1465     (check-next-stream-line-equal _test-output-stream "    (g *(ebp+0xfffffffc))"  "F - test-convert-function-call-with-inout-with-compound-type/7")
 1466     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-call-with-inout-with-compound-type/8")
 1467     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-inout-with-compound-type/9")
 1468     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-inout-with-compound-type/10")
 1469     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-inout-with-compound-type/11")
 1470     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-inout-with-compound-type/12")
 1471     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-inout-with-compound-type/13")
 1472     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-inout-with-compound-type/14")
 1473     (check-next-stream-line-equal _test-output-stream "g:"                      "F - test-convert-function-call-with-inout-with-compound-type/15")
 1474     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-inout-with-compound-type/16")
 1475     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-inout-with-compound-type/17")
 1476     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-inout-with-compound-type/18")
 1477     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-inout-with-compound-type/19")
 1478     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-inout-with-compound-type/20")
 1479     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-inout-with-compound-type/21")
 1480     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-inout-with-compound-type/22")
 1481     # . epilogue
 1482     89/<- %esp 5/r32/ebp
 1483     5d/pop-to-ebp
 1484     c3/return
 1485 
 1486 test-convert-function-call-with-inout-with-type-parameter:
 1487     # . prologue
 1488     55/push-ebp
 1489     89/<- %ebp 4/r32/esp
 1490     # setup
 1491     (clear-stream _test-input-stream)
 1492     (clear-stream $_test-input-buffered-file->buffer)
 1493     (clear-stream _test-output-stream)
 1494     (clear-stream $_test-output-buffered-file->buffer)
 1495     (clear-stream _test-error-stream)
 1496     (clear-stream $_test-error-buffered-file->buffer)
 1497     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1498     68/push 0/imm32
 1499     68/push 0/imm32
 1500     89/<- %edx 4/r32/esp
 1501     (tailor-exit-descriptor %edx 0x10)
 1502     #
 1503     (write _test-input-stream "fn f {\n")
 1504     (write _test-input-stream "  var x: (addr int)\n")
 1505     (write _test-input-stream "  g x\n")
 1506     (write _test-input-stream "}\n")
 1507     (write _test-input-stream "fn g a: (addr _) {\n")
 1508     (write _test-input-stream "}\n")
 1509     # convert
 1510     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1511     # registers except esp clobbered at this point
 1512     # restore ed
 1513     89/<- %edx 4/r32/esp
 1514     (flush _test-output-buffered-file)
 1515     (flush _test-error-buffered-file)
 1516 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1522     # no error; types matched
 1523     (check-stream-equal _test-error-stream  ""  "F - test-convert-function-call-with-inout-with-type-parameter: error stream should be empty")
 1524     # don't bother checking the generated code; that's in the test 'test-local-clobbered-by-fn-output' below
 1525     # don't restore from ebp
 1526     81 0/subop/add %esp 8/imm32
 1527     # . epilogue
 1528     5d/pop-to-ebp
 1529     c3/return
 1530 
 1531 test-convert-function-call-with-incorrect-inout-type:
 1532     # . prologue
 1533     55/push-ebp
 1534     89/<- %ebp 4/r32/esp
 1535     # setup
 1536     (clear-stream _test-input-stream)
 1537     (clear-stream $_test-input-buffered-file->buffer)
 1538     (clear-stream _test-output-stream)
 1539     (clear-stream $_test-output-buffered-file->buffer)
 1540     (clear-stream _test-error-stream)
 1541     (clear-stream $_test-error-buffered-file->buffer)
 1542     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1543     68/push 0/imm32
 1544     68/push 0/imm32
 1545     89/<- %edx 4/r32/esp
 1546     (tailor-exit-descriptor %edx 0x10)
 1547     #
 1548     (write _test-input-stream "fn f {\n")
 1549     (write _test-input-stream "  var x: int\n")
 1550     (write _test-input-stream "  g x\n")
 1551     (write _test-input-stream "}\n")
 1552     (write _test-input-stream "fn g a: foo {\n")
 1553     (write _test-input-stream "}\n")
 1554     # convert
 1555     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1556     # registers except esp clobbered at this point
 1557     # restore ed
 1558     89/<- %edx 4/r32/esp
 1559     (flush _test-output-buffered-file)
 1560     (flush _test-error-buffered-file)
 1561 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1567     # check output
 1568     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-inout-type: output should be empty")
 1569     (check-next-stream-line-equal _test-error-stream  "fn f: call g: type for inout 'x' is not right"  "F - test-convert-function-call-with-incorrect-inout-type: error message")
 1570     # check that stop(1) was called
 1571     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-inout-type: exit status")
 1572     # don't restore from ebp
 1573     81 0/subop/add %esp 8/imm32
 1574     5d/pop-to-ebp
 1575     c3/return
 1576 
 1577 test-convert-function-call-with-inout-with-incorrect-compound-type:
 1578     # . prologue
 1579     55/push-ebp
 1580     89/<- %ebp 4/r32/esp
 1581     # setup
 1582     (clear-stream _test-input-stream)
 1583     (clear-stream $_test-input-buffered-file->buffer)
 1584     (clear-stream _test-output-stream)
 1585     (clear-stream $_test-output-buffered-file->buffer)
 1586     (clear-stream _test-error-stream)
 1587     (clear-stream $_test-error-buffered-file->buffer)
 1588     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1589     68/push 0/imm32
 1590     68/push 0/imm32
 1591     89/<- %edx 4/r32/esp
 1592     (tailor-exit-descriptor %edx 0x10)
 1593     #
 1594     (write _test-input-stream "fn f {\n")
 1595     (write _test-input-stream "  var x: (addr int)\n")
 1596     (write _test-input-stream "  g x\n")
 1597     (write _test-input-stream "}\n")
 1598     (write _test-input-stream "fn g a: (addr bool) {\n")
 1599     (write _test-input-stream "}\n")
 1600     # convert
 1601     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1602     # registers except esp clobbered at this point
 1603     # restore ed
 1604     89/<- %edx 4/r32/esp
 1605     (flush _test-output-buffered-file)
 1606     (flush _test-error-buffered-file)
 1607 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1613     # check output
 1614     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-inout-with-incorrect-compound-type: output should be empty")
 1615     (check-next-stream-line-equal _test-error-stream  "fn f: call g: type for inout 'x' is not right"  "F - test-convert-function-call-with-inout-with-incorrect-compound-type: error message")
 1616     # don't restore from ebp
 1617     81 0/subop/add %esp 8/imm32
 1618     # . epilogue
 1619     5d/pop-to-ebp
 1620     c3/return
 1621 
 1622 test-convert-function-call-with-inout-with-multiple-type-parameters:
 1623     # . prologue
 1624     55/push-ebp
 1625     89/<- %ebp 4/r32/esp
 1626     # setup
 1627     (clear-stream _test-input-stream)
 1628     (clear-stream $_test-input-buffered-file->buffer)
 1629     (clear-stream _test-output-stream)
 1630     (clear-stream $_test-output-buffered-file->buffer)
 1631     (clear-stream _test-error-stream)
 1632     (clear-stream $_test-error-buffered-file->buffer)
 1633     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1634     68/push 0/imm32
 1635     68/push 0/imm32
 1636     89/<- %edx 4/r32/esp
 1637     (tailor-exit-descriptor %edx 0x10)
 1638     #
 1639     (write _test-input-stream "fn f {\n")
 1640     (write _test-input-stream "  var x: (addr int)\n")
 1641     (write _test-input-stream "  var y: (addr int)\n")
 1642     (write _test-input-stream "  g x, y\n")
 1643     (write _test-input-stream "}\n")
 1644     (write _test-input-stream "fn g a: (addr _), b: (addr _) {\n")
 1645     (write _test-input-stream "}\n")
 1646     # convert
 1647     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1648     # registers except esp clobbered at this point
 1649     # restore ed
 1650     89/<- %edx 4/r32/esp
 1651     (flush _test-output-buffered-file)
 1652     (flush _test-error-buffered-file)
 1653 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1659     # no errors
 1660     (check-stream-equal _test-error-stream  ""  "F - test-convert-function-call-with-inout-with-multiple-type-parameters: error stream should be empty")
 1661     # don't bother checking the generated code
 1662     # don't restore from ebp
 1663     81 0/subop/add %esp 8/imm32
 1664     # . epilogue
 1665     5d/pop-to-ebp
 1666     c3/return
 1667 
 1668 test-convert-function-call-with-inout-with-incompatible-type-parameters:
 1669     # . prologue
 1670     55/push-ebp
 1671     89/<- %ebp 4/r32/esp
 1672     # setup
 1673     (clear-stream _test-input-stream)
 1674     (clear-stream $_test-input-buffered-file->buffer)
 1675     (clear-stream _test-output-stream)
 1676     (clear-stream $_test-output-buffered-file->buffer)
 1677     (clear-stream _test-error-stream)
 1678     (clear-stream $_test-error-buffered-file->buffer)
 1679     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1680     68/push 0/imm32
 1681     68/push 0/imm32
 1682     89/<- %edx 4/r32/esp
 1683     (tailor-exit-descriptor %edx 0x10)
 1684     #
 1685     (write _test-input-stream "fn f {\n")
 1686     (write _test-input-stream "  var x: (addr int)\n")
 1687     (write _test-input-stream "  var y: (addr boolean)\n")
 1688     (write _test-input-stream "  g x, y\n")
 1689     (write _test-input-stream "}\n")
 1690     (write _test-input-stream "fn g a: (addr _T), b: (addr _T) {\n")
 1691     (write _test-input-stream "}\n")
 1692     # convert
 1693     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1694     # registers except esp clobbered at this point
 1695     # restore ed
 1696     89/<- %edx 4/r32/esp
 1697     (flush _test-output-buffered-file)
 1698     (flush _test-error-buffered-file)
 1699 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1705     # check output
 1706     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-inout-with-incompatible-type-parameters: output should be empty")
 1707     (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")
 1708     # don't restore from ebp
 1709     81 0/subop/add %esp 8/imm32
 1710     # . epilogue
 1711     5d/pop-to-ebp
 1712     c3/return
 1713 
 1714 test-convert-function-call-with-too-few-inouts:
 1715     # . prologue
 1716     55/push-ebp
 1717     89/<- %ebp 4/r32/esp
 1718     # setup
 1719     (clear-stream _test-input-stream)
 1720     (clear-stream $_test-input-buffered-file->buffer)
 1721     (clear-stream _test-output-stream)
 1722     (clear-stream $_test-output-buffered-file->buffer)
 1723     (clear-stream _test-error-stream)
 1724     (clear-stream $_test-error-buffered-file->buffer)
 1725     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1726     68/push 0/imm32
 1727     68/push 0/imm32
 1728     89/<- %edx 4/r32/esp
 1729     (tailor-exit-descriptor %edx 0x10)
 1730     #
 1731     (write _test-input-stream "fn f {\n")
 1732     (write _test-input-stream "  g\n")
 1733     (write _test-input-stream "}\n")
 1734     (write _test-input-stream "fn g a: int {\n")
 1735     (write _test-input-stream "}\n")
 1736     # convert
 1737     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1738     # registers except esp clobbered at this point
 1739     # restore ed
 1740     89/<- %edx 4/r32/esp
 1741     (flush _test-output-buffered-file)
 1742     (flush _test-error-buffered-file)
 1743 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1749     # check output
 1750     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-few-inouts: output should be empty")
 1751     (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")
 1752     # check that stop(1) was called
 1753     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-few-inouts: exit status")
 1754     # don't restore from ebp
 1755     81 0/subop/add %esp 8/imm32
 1756     5d/pop-to-ebp
 1757     c3/return
 1758 
 1759 test-convert-function-call-with-too-many-inouts:
 1760     # . prologue
 1761     55/push-ebp
 1762     89/<- %ebp 4/r32/esp
 1763     # setup
 1764     (clear-stream _test-input-stream)
 1765     (clear-stream $_test-input-buffered-file->buffer)
 1766     (clear-stream _test-output-stream)
 1767     (clear-stream $_test-output-buffered-file->buffer)
 1768     (clear-stream _test-error-stream)
 1769     (clear-stream $_test-error-buffered-file->buffer)
 1770     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1771     68/push 0/imm32
 1772     68/push 0/imm32
 1773     89/<- %edx 4/r32/esp
 1774     (tailor-exit-descriptor %edx 0x10)
 1775     #
 1776     (write _test-input-stream "fn f {\n")
 1777     (write _test-input-stream "  var x: int\n")
 1778     (write _test-input-stream "  g x\n")
 1779     (write _test-input-stream "}\n")
 1780     (write _test-input-stream "fn g {\n")
 1781     (write _test-input-stream "}\n")
 1782     # convert
 1783     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1784     # registers except esp clobbered at this point
 1785     # restore ed
 1786     89/<- %edx 4/r32/esp
 1787     (flush _test-output-buffered-file)
 1788     (flush _test-error-buffered-file)
 1789 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1795     # check output
 1796     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-many-inouts: output should be empty")
 1797     (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")
 1798     # check that stop(1) was called
 1799     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-many-inouts: exit status")
 1800     # don't restore from ebp
 1801     81 0/subop/add %esp 8/imm32
 1802     5d/pop-to-ebp
 1803     c3/return
 1804 
 1805 test-convert-function-call-with-incorrect-output-type:
 1806     # . prologue
 1807     55/push-ebp
 1808     89/<- %ebp 4/r32/esp
 1809     # setup
 1810     (clear-stream _test-input-stream)
 1811     (clear-stream $_test-input-buffered-file->buffer)
 1812     (clear-stream _test-output-stream)
 1813     (clear-stream $_test-output-buffered-file->buffer)
 1814     (clear-stream _test-error-stream)
 1815     (clear-stream $_test-error-buffered-file->buffer)
 1816     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1817     68/push 0/imm32
 1818     68/push 0/imm32
 1819     89/<- %edx 4/r32/esp
 1820     (tailor-exit-descriptor %edx 0x10)
 1821     #
 1822     (write _test-input-stream "fn f {\n")
 1823     (write _test-input-stream "  var x/eax: int <- g\n")
 1824     (write _test-input-stream "}\n")
 1825     (write _test-input-stream "fn g -> a/eax: foo {\n")
 1826     (write _test-input-stream "}\n")
 1827     # convert
 1828     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1829     # registers except esp clobbered at this point
 1830     # restore ed
 1831     89/<- %edx 4/r32/esp
 1832     (flush _test-output-buffered-file)
 1833     (flush _test-error-buffered-file)
 1834 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1840     # check output
 1841     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-output-type: output should be empty")
 1842     (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")
 1843     # check that stop(1) was called
 1844     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-output-type: exit status")
 1845     # don't restore from ebp
 1846     81 0/subop/add %esp 8/imm32
 1847     5d/pop-to-ebp
 1848     c3/return
 1849 
 1850 test-convert-function-call-with-too-few-outputs:
 1851     # . prologue
 1852     55/push-ebp
 1853     89/<- %ebp 4/r32/esp
 1854     # setup
 1855     (clear-stream _test-input-stream)
 1856     (clear-stream $_test-input-buffered-file->buffer)
 1857     (clear-stream _test-output-stream)
 1858     (clear-stream $_test-output-buffered-file->buffer)
 1859     (clear-stream _test-error-stream)
 1860     (clear-stream $_test-error-buffered-file->buffer)
 1861     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1862     68/push 0/imm32
 1863     68/push 0/imm32
 1864     89/<- %edx 4/r32/esp
 1865     (tailor-exit-descriptor %edx 0x10)
 1866     #
 1867     (write _test-input-stream "fn f {\n")
 1868     (write _test-input-stream "  g\n")
 1869     (write _test-input-stream "}\n")
 1870     (write _test-input-stream "fn g -> a/eax: int {\n")
 1871     (write _test-input-stream "}\n")
 1872     # convert
 1873     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1874     # registers except esp clobbered at this point
 1875     # restore ed
 1876     89/<- %edx 4/r32/esp
 1877     (flush _test-output-buffered-file)
 1878     (flush _test-error-buffered-file)
 1879 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1885     # check output
 1886     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-few-outputs: output should be empty")
 1887     (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")
 1888     # check that stop(1) was called
 1889     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-few-outputs: exit status")
 1890     # don't restore from ebp
 1891     81 0/subop/add %esp 8/imm32
 1892     5d/pop-to-ebp
 1893     c3/return
 1894 
 1895 test-convert-function-call-with-too-many-outputs:
 1896     # . prologue
 1897     55/push-ebp
 1898     89/<- %ebp 4/r32/esp
 1899     # setup
 1900     (clear-stream _test-input-stream)
 1901     (clear-stream $_test-input-buffered-file->buffer)
 1902     (clear-stream _test-output-stream)
 1903     (clear-stream $_test-output-buffered-file->buffer)
 1904     (clear-stream _test-error-stream)
 1905     (clear-stream $_test-error-buffered-file->buffer)
 1906     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1907     68/push 0/imm32
 1908     68/push 0/imm32
 1909     89/<- %edx 4/r32/esp
 1910     (tailor-exit-descriptor %edx 0x10)
 1911     #
 1912     (write _test-input-stream "fn f {\n")
 1913     (write _test-input-stream "  var x/eax: int <- g\n")
 1914     (write _test-input-stream "}\n")
 1915     (write _test-input-stream "fn g {\n")
 1916     (write _test-input-stream "}\n")
 1917     # convert
 1918     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1919     # registers except esp clobbered at this point
 1920     # restore ed
 1921     89/<- %edx 4/r32/esp
 1922     (flush _test-output-buffered-file)
 1923     (flush _test-error-buffered-file)
 1924 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1930     # check output
 1931     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-many-outputs: output should be empty")
 1932     (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")
 1933     # check that stop(1) was called
 1934     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-many-outputs: exit status")
 1935     # don't restore from ebp
 1936     81 0/subop/add %esp 8/imm32
 1937     5d/pop-to-ebp
 1938     c3/return
 1939 
 1940 test-convert-function-call-with-incorrect-output-register:
 1941     # . prologue
 1942     55/push-ebp
 1943     89/<- %ebp 4/r32/esp
 1944     # setup
 1945     (clear-stream _test-input-stream)
 1946     (clear-stream $_test-input-buffered-file->buffer)
 1947     (clear-stream _test-output-stream)
 1948     (clear-stream $_test-output-buffered-file->buffer)
 1949     (clear-stream _test-error-stream)
 1950     (clear-stream $_test-error-buffered-file->buffer)
 1951     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1952     68/push 0/imm32
 1953     68/push 0/imm32
 1954     89/<- %edx 4/r32/esp
 1955     (tailor-exit-descriptor %edx 0x10)
 1956     #
 1957     (write _test-input-stream "fn f {\n")
 1958     (write _test-input-stream "  var x/ecx: int <- g\n")
 1959     (write _test-input-stream "}\n")
 1960     (write _test-input-stream "fn g -> a/eax: int {\n")
 1961     (write _test-input-stream "}\n")
 1962     # convert
 1963     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1964     # registers except esp clobbered at this point
 1965     # restore ed
 1966     89/<- %edx 4/r32/esp
 1967     (flush _test-output-buffered-file)
 1968     (flush _test-error-buffered-file)
 1969 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1975     # check output
 1976     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-output-register: output should be empty")
 1977     (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")
 1978     # check that stop(1) was called
 1979     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-output-register: exit status")
 1980     # don't restore from ebp
 1981     81 0/subop/add %esp 8/imm32
 1982     5d/pop-to-ebp
 1983     c3/return
 1984 
 1985 test-convert-function-with-local-var-dereferenced:
 1986     # . prologue
 1987     55/push-ebp
 1988     89/<- %ebp 4/r32/esp
 1989     # setup
 1990     (clear-stream _test-input-stream)
 1991     (clear-stream $_test-input-buffered-file->buffer)
 1992     (clear-stream _test-output-stream)
 1993     (clear-stream $_test-output-buffered-file->buffer)
 1994     #
 1995     (write _test-input-stream "fn foo {\n")
 1996     (write _test-input-stream "  var x/ecx: (addr int) <- copy 0\n")
 1997     (write _test-input-stream "  increment *x\n")
 1998     (write _test-input-stream "}\n")
 1999     # convert
 2000     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2001     (flush _test-output-buffered-file)
 2002 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2008     # check output
 2009     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-dereferenced/0")
 2010     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-dereferenced/1")
 2011     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-dereferenced/2")
 2012     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-dereferenced/3")
 2013     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-dereferenced/4")
 2014     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-dereferenced/5")
 2015     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-dereferenced/6")
 2016     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-local-var-dereferenced/7")
 2017     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *ecx"  "F - test-convert-function-with-local-var-dereferenced/8")
 2018     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-dereferenced/9")
 2019     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-dereferenced/10")
 2020     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-dereferenced/11")
 2021     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-dereferenced/12")
 2022     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-dereferenced/13")
 2023     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-dereferenced/14")
 2024     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-dereferenced/15")
 2025     # . epilogue
 2026     89/<- %esp 5/r32/ebp
 2027     5d/pop-to-ebp
 2028     c3/return
 2029 
 2030 # variables of type 'byte' are not allowed on the stack
 2031 test-convert-function-with-byte-operations:
 2032     # . prologue
 2033     55/push-ebp
 2034     89/<- %ebp 4/r32/esp
 2035     # setup
 2036     (clear-stream _test-input-stream)
 2037     (clear-stream $_test-input-buffered-file->buffer)
 2038     (clear-stream _test-output-stream)
 2039     (clear-stream $_test-output-buffered-file->buffer)
 2040     #
 2041     (write _test-input-stream "fn foo {\n")
 2042     (write _test-input-stream "  var x/eax: byte <- copy 0\n")
 2043     (write _test-input-stream "  var y/ecx: byte <- copy 0\n")
 2044     (write _test-input-stream "  y <- copy-byte x\n")
 2045     (write _test-input-stream "  var z/edx: (addr byte) <- copy 0\n")
 2046     (write _test-input-stream "  y <- copy-byte *z\n")
 2047     (write _test-input-stream "  copy-byte-to *z, x\n")
 2048     (write _test-input-stream "}\n")
 2049     # convert
 2050     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2051     (flush _test-output-buffered-file)
 2052 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2058     # check output
 2059     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-function-with-byte-operations/0")
 2060     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-function-with-byte-operations/1")
 2061     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-function-with-byte-operations/2")
 2062     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-function-with-byte-operations/3")
 2063     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-function-with-byte-operations/4")
 2064     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-function-with-byte-operations/5")
 2065     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-function-with-byte-operations/6")
 2066     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-function-with-byte-operations/7")
 2067     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-function-with-byte-operations/8")
 2068     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"                  "F - test-convert-function-with-byte-operations/9")
 2069     (check-next-stream-line-equal _test-output-stream "    8a/byte-> %eax 0x00000001/r32"           "F - test-convert-function-with-byte-operations/10")
 2070     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %edx"                    "F - test-convert-function-with-byte-operations/11")
 2071     (check-next-stream-line-equal _test-output-stream "    ba/copy-to-edx 0/imm32"                  "F - test-convert-function-with-byte-operations/12")
 2072     (check-next-stream-line-equal _test-output-stream "    8a/byte-> *edx 0x00000001/r32"           "F - test-convert-function-with-byte-operations/13")
 2073     (check-next-stream-line-equal _test-output-stream "    88/byte<- *edx 0x00000000/r32"           "F - test-convert-function-with-byte-operations/14")
 2074     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %edx"                     "F - test-convert-function-with-byte-operations/15")
 2075     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-function-with-byte-operations/16")
 2076     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-function-with-byte-operations/17")
 2077     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-function-with-byte-operations/18")
 2078     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-function-with-byte-operations/19")
 2079     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-function-with-byte-operations/20")
 2080     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-function-with-byte-operations/21")
 2081     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-function-with-byte-operations/22")
 2082     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-function-with-byte-operations/23")
 2083     # . epilogue
 2084     89/<- %esp 5/r32/ebp
 2085     5d/pop-to-ebp
 2086     c3/return
 2087 
 2088 # variables of type 'byte' _can_ be function args. They then occupy 4 bytes.
 2089 test-copy-byte-var-from-fn-arg:
 2090     # . prologue
 2091     55/push-ebp
 2092     89/<- %ebp 4/r32/esp
 2093     # setup
 2094     (clear-stream _test-input-stream)
 2095     (clear-stream $_test-input-buffered-file->buffer)
 2096     (clear-stream _test-output-stream)
 2097     (clear-stream $_test-output-buffered-file->buffer)
 2098     #
 2099     (write _test-input-stream "fn foo x: byte, y: int {\n")
 2100     (write _test-input-stream "  var a/eax: byte <- copy x\n")
 2101     (write _test-input-stream "  var b/eax: int <- copy y\n")
 2102     (write _test-input-stream "}\n")
 2103     # convert
 2104     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2105     (flush _test-output-buffered-file)
 2106 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2112     # check output
 2113     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-copy-byte-from-fn-arg/0")
 2114     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-copy-byte-from-fn-arg/1")
 2115     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-copy-byte-from-fn-arg/2")
 2116     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-copy-byte-from-fn-arg/3")
 2117     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-copy-byte-from-fn-arg/4")
 2118     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-copy-byte-from-fn-arg/5")
 2119     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-copy-byte-from-fn-arg/6")
 2120     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-copy-byte-from-fn-arg/7")
 2121     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x0000000c) 0x00000000/r32"  "F - test-copy-byte-from-fn-arg/8")
 2122     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"   "F - test-copy-byte-from-fn-arg/9")
 2123     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-copy-byte-from-fn-arg/10")
 2124     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-copy-byte-from-fn-arg/11")
 2125     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-copy-byte-from-fn-arg/12")
 2126     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-copy-byte-from-fn-arg/13")
 2127     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-copy-byte-from-fn-arg/14")
 2128     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-copy-byte-from-fn-arg/15")
 2129     # . epilogue
 2130     89/<- %esp 5/r32/ebp
 2131     5d/pop-to-ebp
 2132     c3/return
 2133 
 2134 test-convert-compare-register-with-literal:
 2135     # . prologue
 2136     55/push-ebp
 2137     89/<- %ebp 4/r32/esp
 2138     # setup
 2139     (clear-stream _test-input-stream)
 2140     (clear-stream $_test-input-buffered-file->buffer)
 2141     (clear-stream _test-output-stream)
 2142     (clear-stream $_test-output-buffered-file->buffer)
 2143     #
 2144     (write _test-input-stream "fn foo {\n")
 2145     (write _test-input-stream "  var x/ecx: int <- copy 0\n")
 2146     (write _test-input-stream "  compare x, 0\n")
 2147     (write _test-input-stream "}\n")
 2148     # convert
 2149     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2150     (flush _test-output-buffered-file)
 2151 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2157     # check output
 2158     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-compare-register-with-literal/0")
 2159     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-compare-register-with-literal/1")
 2160     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-compare-register-with-literal/2")
 2161     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-compare-register-with-literal/3")
 2162     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-compare-register-with-literal/4")
 2163     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-compare-register-with-literal/5")
 2164     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
 2165     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-compare-register-with-literal/7")
 2166     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %ecx 0/imm32"  "F - test-convert-compare-register-with-literal/8")
 2167     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
 2168     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-compare-register-with-literal/10")
 2169     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-compare-register-with-literal/11")
 2170     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-compare-register-with-literal/12")
 2171     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-compare-register-with-literal/13")
 2172     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-compare-register-with-literal/14")
 2173     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-compare-register-with-literal/15")
 2174     # . epilogue
 2175     89/<- %esp 5/r32/ebp
 2176     5d/pop-to-ebp
 2177     c3/return
 2178 
 2179 test-unknown-variable:
 2180     # . prologue
 2181     55/push-ebp
 2182     89/<- %ebp 4/r32/esp
 2183     # setup
 2184     (clear-stream _test-input-stream)
 2185     (clear-stream $_test-input-buffered-file->buffer)
 2186     (clear-stream _test-output-stream)
 2187     (clear-stream $_test-output-buffered-file->buffer)
 2188     (clear-stream _test-error-stream)
 2189     (clear-stream $_test-error-buffered-file->buffer)
 2190     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 2191     68/push 0/imm32
 2192     68/push 0/imm32
 2193     89/<- %edx 4/r32/esp
 2194     (tailor-exit-descriptor %edx 0x10)
 2195     #
 2196     (write _test-input-stream "fn foo {\n")
 2197     (write _test-input-stream "  compare x, 0\n")
 2198     (write _test-input-stream "}\n")
 2199     # convert
 2200     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 2201     # registers except esp clobbered at this point
 2202     # restore ed
 2203     89/<- %edx 4/r32/esp
 2204     (flush _test-output-buffered-file)
 2205     (flush _test-error-buffered-file)
 2206 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 2212     # check output
 2213     (check-stream-equal _test-output-stream  ""  "F - test-unknown-variable: output should be empty")
 2214     (check-next-stream-line-equal _test-error-stream  "fn foo: unknown variable 'x'"  "F - test-unknown-variable: error message")
 2215     # check that stop(1) was called
 2216     (check-ints-equal *(edx+4) 2 "F - test-unknown-variable: exit status")
 2217     # don't restore from ebp
 2218     81 0/subop/add %esp 8/imm32
 2219     # . epilogue
 2220     5d/pop-to-ebp
 2221     c3/return
 2222 
 2223 test-convert-function-with-local-var-in-block:
 2224     # . prologue
 2225     55/push-ebp
 2226     89/<- %ebp 4/r32/esp
 2227     # setup
 2228     (clear-stream _test-input-stream)
 2229     (clear-stream $_test-input-buffered-file->buffer)
 2230     (clear-stream _test-output-stream)
 2231     (clear-stream $_test-output-buffered-file->buffer)
 2232     #
 2233     (write _test-input-stream "fn foo {\n")
 2234     (write _test-input-stream "  {\n")
 2235     (write _test-input-stream "    var x: int\n")
 2236     (write _test-input-stream "    increment x\n")
 2237     (write _test-input-stream "  }\n")
 2238     (write _test-input-stream "}\n")
 2239     # convert
 2240     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2241     (flush _test-output-buffered-file)
 2242 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2248     # check output
 2249     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-block/0")
 2250     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-block/1")
 2251     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-block/2")
 2252     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-block/3")
 2253     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-block/4")
 2254     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-block/5")
 2255     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-block/6")
 2256     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-local-var-in-block/7")
 2257     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-block/8")
 2258     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-block/9")
 2259     (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")
 2260     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-block/11")
 2261     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-local-var-in-block/12")
 2262     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-block/13")
 2263     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-block/14")
 2264     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-block/15")
 2265     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-block/16")
 2266     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-block/17")
 2267     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-block/18")
 2268     # . epilogue
 2269     89/<- %esp 5/r32/ebp
 2270     5d/pop-to-ebp
 2271     c3/return
 2272 
 2273 test-convert-function-with-local-var-in-named-block:
 2274     # . prologue
 2275     55/push-ebp
 2276     89/<- %ebp 4/r32/esp
 2277     # setup
 2278     (clear-stream _test-input-stream)
 2279     (clear-stream $_test-input-buffered-file->buffer)
 2280     (clear-stream _test-output-stream)
 2281     (clear-stream $_test-output-buffered-file->buffer)
 2282     #
 2283     (write _test-input-stream "fn foo {\n")
 2284     (write _test-input-stream "  $bar: {\n")
 2285     (write _test-input-stream "    var x: int\n")
 2286     (write _test-input-stream "    increment x\n")
 2287     (write _test-input-stream "  }\n")
 2288     (write _test-input-stream "}\n")
 2289     # convert
 2290     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2291     (flush _test-output-buffered-file)
 2292 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2298     # check output
 2299     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-named-block/0")
 2300     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-named-block/1")
 2301     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-named-block/2")
 2302     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-named-block/3")
 2303     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-named-block/4")
 2304     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-named-block/5")
 2305     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-named-block/6")
 2306     (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-local-var-in-named-block/7")
 2307     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-named-block/8")
 2308     (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")
 2309     (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")
 2310     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-named-block/11")
 2311     (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-local-var-in-named-block/12")
 2312     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-named-block/13")
 2313     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-named-block/14")
 2314     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-named-block/15")
 2315     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-named-block/16")
 2316     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-named-block/17")
 2317     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-named-block/18")
 2318     # . epilogue
 2319     89/<- %esp 5/r32/ebp
 2320     5d/pop-to-ebp
 2321     c3/return
 2322 
 2323 test-unknown-variable-in-named-block:
 2324     # . prologue
 2325     55/push-ebp
 2326     89/<- %ebp 4/r32/esp
 2327     # setup
 2328     (clear-stream _test-input-stream)
 2329     (clear-stream $_test-input-buffered-file->buffer)
 2330     (clear-stream _test-output-stream)
 2331     (clear-stream $_test-output-buffered-file->buffer)
 2332     (clear-stream _test-error-stream)
 2333     (clear-stream $_test-error-buffered-file->buffer)
 2334     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 2335     68/push 0/imm32
 2336     68/push 0/imm32
 2337     89/<- %edx 4/r32/esp
 2338     (tailor-exit-descriptor %edx 0x10)
 2339     #
 2340     (write _test-input-stream "fn foo {\n")
 2341     (write _test-input-stream "  $a: {\n")
 2342     (write _test-input-stream "    compare x, 0\n")
 2343     (write _test-input-stream "  }\n")
 2344     (write _test-input-stream "}\n")
 2345     # convert
 2346     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 2347     # registers except esp clobbered at this point
 2348     # restore ed
 2349     89/<- %edx 4/r32/esp
 2350     (flush _test-output-buffered-file)
 2351     (flush _test-error-buffered-file)
 2352 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 2358     # check output
 2359     (check-stream-equal _test-output-stream  ""  "F - test-unknown-variable-in-named-block: output should be empty")
 2360     (check-next-stream-line-equal _test-error-stream  "fn foo: unknown variable 'x'"  "F - test-unknown-variable-in-named-block: error message")
 2361     # check that stop(1) was called
 2362     (check-ints-equal *(edx+4) 2 "F - test-unknown-variable-in-named-block: exit status")
 2363     # don't restore from ebp
 2364     81 0/subop/add %esp 8/imm32
 2365     # . epilogue
 2366     5d/pop-to-ebp
 2367     c3/return
 2368 
 2369 test-always-shadow-outermost-reg-vars-in-function:
 2370     # . prologue
 2371     55/push-ebp
 2372     89/<- %ebp 4/r32/esp
 2373     # setup
 2374     (clear-stream _test-input-stream)
 2375     (clear-stream $_test-input-buffered-file->buffer)
 2376     (clear-stream _test-output-stream)
 2377     (clear-stream $_test-output-buffered-file->buffer)
 2378     #
 2379     (write _test-input-stream "fn foo {\n")
 2380     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2381     (write _test-input-stream "}\n")
 2382     # convert
 2383     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2384     (flush _test-output-buffered-file)
 2385 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2391     # check output
 2392     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-always-shadow-outermost-reg-vars-in-function/0")
 2393     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-always-shadow-outermost-reg-vars-in-function/1")
 2394     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-always-shadow-outermost-reg-vars-in-function/2")
 2395     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-always-shadow-outermost-reg-vars-in-function/3")
 2396     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-always-shadow-outermost-reg-vars-in-function/4")
 2397     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-always-shadow-outermost-reg-vars-in-function/5")
 2398     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
 2399     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-always-shadow-outermost-reg-vars-in-function/8")
 2400     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
 2401     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-always-shadow-outermost-reg-vars-in-function/12")
 2402     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-always-shadow-outermost-reg-vars-in-function/13")
 2403     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-always-shadow-outermost-reg-vars-in-function/14")
 2404     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-always-shadow-outermost-reg-vars-in-function/15")
 2405     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-always-shadow-outermost-reg-vars-in-function/16")
 2406     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-always-shadow-outermost-reg-vars-in-function/17")
 2407     # . epilogue
 2408     89/<- %esp 5/r32/ebp
 2409     5d/pop-to-ebp
 2410     c3/return
 2411 
 2412 _pending-test-clobber-dead-local:
 2413     # . prologue
 2414     55/push-ebp
 2415     89/<- %ebp 4/r32/esp
 2416     # setup
 2417     (clear-stream _test-input-stream)
 2418     (clear-stream $_test-input-buffered-file->buffer)
 2419     (clear-stream _test-output-stream)
 2420     (clear-stream $_test-output-buffered-file->buffer)
 2421     #
 2422     (write _test-input-stream "fn foo {\n")
 2423     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2424     (write _test-input-stream "  {\n")
 2425     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 2426     (write _test-input-stream "  }\n")
 2427     (write _test-input-stream "}\n")
 2428     # convert
 2429     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2430     (flush _test-output-buffered-file)
 2431 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2437     # check output
 2438     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-clobber-dead-local/0")
 2439     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-clobber-dead-local/1")
 2440     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-clobber-dead-local/2")
 2441     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-clobber-dead-local/3")
 2442     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-clobber-dead-local/4")
 2443     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-clobber-dead-local/5")
 2444     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-clobber-dead-local/6")
 2445     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-clobber-dead-local/7")
 2446     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-clobber-dead-local/8")
 2447     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-clobber-dead-local/9")
 2448     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-clobber-dead-local/10")  # no push/pop here
 2449     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-clobber-dead-local/11")
 2450     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-clobber-dead-local/12")
 2451     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-clobber-dead-local/13")
 2452     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-clobber-dead-local/14")
 2453     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-clobber-dead-local/15")
 2454     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-clobber-dead-local/16")
 2455     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-clobber-dead-local/17")
 2456     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-clobber-dead-local/18")
 2457     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-clobber-dead-local/19")
 2458     # . epilogue
 2459     89/<- %esp 5/r32/ebp
 2460     5d/pop-to-ebp
 2461     c3/return
 2462 
 2463 test-shadow-live-local:
 2464     # . prologue
 2465     55/push-ebp
 2466     89/<- %ebp 4/r32/esp
 2467     # setup
 2468     (clear-stream _test-input-stream)
 2469     (clear-stream $_test-input-buffered-file->buffer)
 2470     (clear-stream _test-output-stream)
 2471     (clear-stream $_test-output-buffered-file->buffer)
 2472     #
 2473     (write _test-input-stream "fn foo {\n")
 2474     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2475     (write _test-input-stream "  {\n")
 2476     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 2477     (write _test-input-stream "  }\n")
 2478     (write _test-input-stream "  x <- increment\n")
 2479     (write _test-input-stream "}\n")
 2480     # convert
 2481     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2482     (flush _test-output-buffered-file)
 2483 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2489     # check output
 2490     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-live-local/0")
 2491     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-live-local/1")
 2492     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-live-local/2")
 2493     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-live-local/3")
 2494     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-live-local/4")
 2495     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-live-local/5")
 2496     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-live-local/6")
 2497     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-live-local/7")
 2498     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-live-local/8")
 2499     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-live-local/9")
 2500     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-live-local/10")
 2501     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-live-local/11")
 2502     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-live-local/12")
 2503     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-live-local/13")
 2504     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-live-local/14")
 2505     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-live-local/15")
 2506     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-live-local/16")
 2507     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-live-local/17")
 2508     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-live-local/18")
 2509     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-live-local/19")
 2510     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-live-local/20")
 2511     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-live-local/21")
 2512     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-live-local/22")
 2513     # . epilogue
 2514     89/<- %esp 5/r32/ebp
 2515     5d/pop-to-ebp
 2516     c3/return
 2517 
 2518 test-shadow-name:
 2519     # . prologue
 2520     55/push-ebp
 2521     89/<- %ebp 4/r32/esp
 2522     # setup
 2523     (clear-stream _test-input-stream)
 2524     (clear-stream $_test-input-buffered-file->buffer)
 2525     (clear-stream _test-output-stream)
 2526     (clear-stream $_test-output-buffered-file->buffer)
 2527     #
 2528     (write _test-input-stream "fn foo {\n")
 2529     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2530     (write _test-input-stream "  {\n")
 2531     (write _test-input-stream "    var x/edx: int <- copy 4\n")
 2532     (write _test-input-stream "  }\n")
 2533     (write _test-input-stream "  x <- increment\n")
 2534     (write _test-input-stream "}\n")
 2535     # convert
 2536     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2537     (flush _test-output-buffered-file)
 2538 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2544     # check output
 2545     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-name/0")
 2546     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-name/1")
 2547     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-name/2")
 2548     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-name/3")
 2549     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-name/4")
 2550     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-name/5")
 2551     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-name/6")
 2552     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-name/7")
 2553     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-name/8")
 2554     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-name/9")
 2555     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %edx"  "F - test-shadow-name/10")
 2556     (check-next-stream-line-equal _test-output-stream "      ba/copy-to-edx 4/imm32"  "F - test-shadow-name/11")
 2557     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %edx" "F - test-shadow-name/12")
 2558     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-name/13")
 2559     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-name/14")
 2560     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-name/15")
 2561     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-name/16")
 2562     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-name/17")
 2563     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-name/18")
 2564     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-name/19")
 2565     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-name/20")
 2566     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-name/21")
 2567     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-name/22")
 2568     # . epilogue
 2569     89/<- %esp 5/r32/ebp
 2570     5d/pop-to-ebp
 2571     c3/return
 2572 
 2573 test-shadow-name-2:
 2574     # . prologue
 2575     55/push-ebp
 2576     89/<- %ebp 4/r32/esp
 2577     # setup
 2578     (clear-stream _test-input-stream)
 2579     (clear-stream $_test-input-buffered-file->buffer)
 2580     (clear-stream _test-output-stream)
 2581     (clear-stream $_test-output-buffered-file->buffer)
 2582     #
 2583     (write _test-input-stream "fn foo {\n")
 2584     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2585     (write _test-input-stream "  {\n")
 2586     (write _test-input-stream "    var x/edx: int <- copy 4\n")
 2587     (write _test-input-stream "    var y/ecx: int <- copy 5\n")
 2588     (write _test-input-stream "  }\n")
 2589     (write _test-input-stream "  x <- increment\n")
 2590     (write _test-input-stream "}\n")
 2591     # convert
 2592     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2593     (flush _test-output-buffered-file)
 2594 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2600     # check output
 2601     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-name-2/0")
 2602     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-name-2/1")
 2603     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-name-2/2")
 2604     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-name-2/3")
 2605     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-name-2/4")
 2606     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-name-2/5")
 2607     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-name-2/6")
 2608     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-name-2/7")
 2609     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-name-2/8")
 2610     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-name-2/9")
 2611     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %edx"  "F - test-shadow-name-2/10")
 2612     (check-next-stream-line-equal _test-output-stream "      ba/copy-to-edx 4/imm32"  "F - test-shadow-name-2/11")
 2613     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-name-2/12")
 2614     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 5/imm32"  "F - test-shadow-name-2/13")
 2615     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-name-2/14")
 2616     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %edx" "F - test-shadow-name-2/15")
 2617     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-name-2/16")
 2618     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-name-2/17")
 2619     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-name-2/18")
 2620     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-name-2/19")
 2621     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-name-2/20")
 2622     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-name-2/21")
 2623     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-name-2/22")
 2624     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-name-2/23")
 2625     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-name-2/24")
 2626     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-name-2/25")
 2627     # . epilogue
 2628     89/<- %esp 5/r32/ebp
 2629     5d/pop-to-ebp
 2630     c3/return
 2631 
 2632 test-do-not-spill-same-register-in-block:
 2633     # . prologue
 2634     55/push-ebp
 2635     89/<- %ebp 4/r32/esp
 2636     # setup
 2637     (clear-stream _test-input-stream)
 2638     (clear-stream $_test-input-buffered-file->buffer)
 2639     (clear-stream _test-output-stream)
 2640     (clear-stream $_test-output-buffered-file->buffer)
 2641     #
 2642     (write _test-input-stream "fn foo {\n")
 2643     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2644     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2645     (write _test-input-stream "  y <- increment\n")
 2646     (write _test-input-stream "}\n")
 2647     # convert
 2648     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2649     (flush _test-output-buffered-file)
 2650 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2656     # check output
 2657     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-do-not-spill-same-register-in-block/0")
 2658     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-do-not-spill-same-register-in-block/1")
 2659     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-do-not-spill-same-register-in-block/2")
 2660     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-do-not-spill-same-register-in-block/3")
 2661     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-do-not-spill-same-register-in-block/4")
 2662     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-do-not-spill-same-register-in-block/5")
 2663     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-do-not-spill-same-register-in-block/6")
 2664     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-do-not-spill-same-register-in-block/7")
 2665     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-do-not-spill-same-register-in-block/8")
 2666     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-do-not-spill-same-register-in-block/9")
 2667     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-do-not-spill-same-register-in-block/10")
 2668     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-do-not-spill-same-register-in-block/11")
 2669     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-do-not-spill-same-register-in-block/12")
 2670     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-do-not-spill-same-register-in-block/13")
 2671     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-do-not-spill-same-register-in-block/14")
 2672     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-do-not-spill-same-register-in-block/15")
 2673     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-do-not-spill-same-register-in-block/16")
 2674     # . epilogue
 2675     89/<- %esp 5/r32/ebp
 2676     5d/pop-to-ebp
 2677     c3/return
 2678 
 2679 test-spill-different-register-in-block:
 2680     # . prologue
 2681     55/push-ebp
 2682     89/<- %ebp 4/r32/esp
 2683     # setup
 2684     (clear-stream _test-input-stream)
 2685     (clear-stream $_test-input-buffered-file->buffer)
 2686     (clear-stream _test-output-stream)
 2687     (clear-stream $_test-output-buffered-file->buffer)
 2688     #
 2689     (write _test-input-stream "fn foo {\n")
 2690     (write _test-input-stream "  var x/eax: int <- copy 3\n")
 2691     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2692     (write _test-input-stream "  y <- increment\n")
 2693     (write _test-input-stream "}\n")
 2694     # convert
 2695     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2696     (flush _test-output-buffered-file)
 2697 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2703     # check output
 2704     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-spill-different-register-in-block/0")
 2705     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-spill-different-register-in-block/1")
 2706     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-spill-different-register-in-block/2")
 2707     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-spill-different-register-in-block/3")
 2708     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-spill-different-register-in-block/4")
 2709     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-spill-different-register-in-block/5")
 2710     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-spill-different-register-in-block/6")
 2711     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-spill-different-register-in-block/7")
 2712     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-spill-different-register-in-block/8")
 2713     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-spill-different-register-in-block/9")
 2714     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-spill-different-register-in-block/10")
 2715     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-spill-different-register-in-block/11")
 2716     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-spill-different-register-in-block/12")
 2717     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-spill-different-register-in-block/13")
 2718     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-spill-different-register-in-block/14")
 2719     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-spill-different-register-in-block/15")
 2720     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-spill-different-register-in-block/16")
 2721     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-spill-different-register-in-block/17")
 2722     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-spill-different-register-in-block/18")
 2723     # . epilogue
 2724     89/<- %esp 5/r32/ebp
 2725     5d/pop-to-ebp
 2726     c3/return
 2727 
 2728 test-shadow-live-output:
 2729     # . prologue
 2730     55/push-ebp
 2731     89/<- %ebp 4/r32/esp
 2732     # setup
 2733     (clear-stream _test-input-stream)
 2734     (clear-stream $_test-input-buffered-file->buffer)
 2735     (clear-stream _test-output-stream)
 2736     (clear-stream $_test-output-buffered-file->buffer)
 2737     #
 2738     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2739     (write _test-input-stream "  x <- copy 3\n")
 2740     (write _test-input-stream "  {\n")
 2741     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 2742     (write _test-input-stream "  }\n")
 2743     (write _test-input-stream "  x <- increment\n")
 2744     (write _test-input-stream "}\n")
 2745     # convert
 2746     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2747     (flush _test-output-buffered-file)
 2748 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2754     # check output
 2755     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-live-output/0")
 2756     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-live-output/1")
 2757     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-live-output/2")
 2758     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-live-output/3")
 2759     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-live-output/4")
 2760     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-live-output/5")
 2761     (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
 2762     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-live-output/8")
 2763     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-live-output/9")
 2764     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-live-output/10")
 2765     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-live-output/11")
 2766     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-live-output/12")
 2767     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-live-output/13")
 2768     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-live-output/14")
 2769     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-live-output/15")
 2770     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-live-output/17")
 2771     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-live-output/18")
 2772     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-live-output/19")
 2773     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-live-output/20")
 2774     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-live-output/21")
 2775     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-live-output/21")
 2776     # . epilogue
 2777     89/<- %esp 5/r32/ebp
 2778     5d/pop-to-ebp
 2779     c3/return
 2780 
 2781 test-stmt-defines-output-in-same-register-as-inout:
 2782     # . prologue
 2783     55/push-ebp
 2784     89/<- %ebp 4/r32/esp
 2785     # setup
 2786     (clear-stream _test-input-stream)
 2787     (clear-stream $_test-input-buffered-file->buffer)
 2788     (clear-stream _test-output-stream)
 2789     (clear-stream $_test-output-buffered-file->buffer)
 2790     (clear-stream _test-error-stream)
 2791     (clear-stream $_test-error-buffered-file->buffer)
 2792     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 2793     68/push 0/imm32
 2794     68/push 0/imm32
 2795     89/<- %edx 4/r32/esp
 2796     (tailor-exit-descriptor %edx 0x10)
 2797     #
 2798     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2799     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2800     (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
 2801     (write _test-input-stream "}\n")
 2802     # convert
 2803     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 2804     # registers except esp clobbered at this point
 2805     # restore ed
 2806     89/<- %edx 4/r32/esp
 2807     (flush _test-output-buffered-file)
 2808     (flush _test-error-buffered-file)
 2809 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 2815     # no error; we looked up 'y' correctly before pushing the binding for 'x'
 2816     (check-stream-equal _test-error-stream  ""  "F - test-stmt-defines-output-in-same-register-as-inout: error stream should be empty")
 2817     # don't bother checking the generated code; that's in the test 'test-local-clobbered-by-fn-output' below
 2818     # don't restore from ebp
 2819     81 0/subop/add %esp 8/imm32
 2820     # . epilogue
 2821     5d/pop-to-ebp
 2822     c3/return
 2823 
 2824 test-local-clobbered-by-fn-output:
 2825     # . prologue
 2826     55/push-ebp
 2827     89/<- %ebp 4/r32/esp
 2828     # setup
 2829     (clear-stream _test-input-stream)
 2830     (clear-stream $_test-input-buffered-file->buffer)
 2831     (clear-stream _test-output-stream)
 2832     (clear-stream $_test-output-buffered-file->buffer)
 2833     #
 2834     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2835     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2836     (write _test-input-stream "  x <- copy y\n")
 2837     (write _test-input-stream "}\n")
 2838     # convert
 2839     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2840     (flush _test-output-buffered-file)
 2841 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2847     # check output
 2848     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-local-clobbered-by-fn-output/0")
 2849     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-local-clobbered-by-fn-output/1")
 2850     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-local-clobbered-by-fn-output/2")
 2851     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-local-clobbered-by-fn-output/3")
 2852     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-local-clobbered-by-fn-output/4")
 2853     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-local-clobbered-by-fn-output/5")
 2854     (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
 2855     (check-next-stream-line-equal _test-output-stream "    89/<- %ecx 0x00000001/r32"  "F - test-local-clobbered-by-fn-output/7")
 2856     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-local-clobbered-by-fn-output/8")
 2857     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-local-clobbered-by-fn-output/9")
 2858     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-local-clobbered-by-fn-output/10")
 2859     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-local-clobbered-by-fn-output/11")
 2860     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-local-clobbered-by-fn-output/12")
 2861     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-local-clobbered-by-fn-output/13")
 2862     # . epilogue
 2863     89/<- %esp 5/r32/ebp
 2864     5d/pop-to-ebp
 2865     c3/return
 2866 
 2867 test-read-output:
 2868     # . prologue
 2869     55/push-ebp
 2870     89/<- %ebp 4/r32/esp
 2871     # setup
 2872     (clear-stream _test-input-stream)
 2873     (clear-stream $_test-input-buffered-file->buffer)
 2874     (clear-stream _test-output-stream)
 2875     (clear-stream $_test-output-buffered-file->buffer)
 2876     #
 2877     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2878     (write _test-input-stream "  x <- copy 0x34\n")
 2879     (write _test-input-stream "  compare x, 0x35\n")
 2880     (write _test-input-stream "}\n")
 2881     # convert
 2882     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2883     (flush _test-output-buffered-file)
 2884 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2890     # check output
 2891     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-read-output/0")
 2892     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-read-output/1")
 2893     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-read-output/2")
 2894     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-read-output/3")
 2895     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-read-output/4")
 2896     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-read-output/5")
 2897     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0x34/imm32"  "F - test-read-output/6")
 2898     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %ecx 0x35/imm32"  "F - test-read-output/7")
 2899     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-read-output/8")
 2900     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-read-output/9")
 2901     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-read-output/10")
 2902     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-read-output/11")
 2903     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-read-output/12")
 2904     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-read-output/13")
 2905     # . epilogue
 2906     89/<- %esp 5/r32/ebp
 2907     5d/pop-to-ebp
 2908     c3/return
 2909 
 2910 test-fn-output-written-in-inner-block:
 2911     # . prologue
 2912     55/push-ebp
 2913     89/<- %ebp 4/r32/esp
 2914     # setup
 2915     (clear-stream _test-input-stream)
 2916     (clear-stream $_test-input-buffered-file->buffer)
 2917     (clear-stream _test-output-stream)
 2918     (clear-stream $_test-output-buffered-file->buffer)
 2919     #
 2920     (write _test-input-stream "fn foo -> out/edi: int {\n")
 2921     (write _test-input-stream "  var a/eax: int <- copy 3\n")  # define outer local
 2922     (write _test-input-stream "  {\n")
 2923     (write _test-input-stream "    var a/ecx: int <- copy 4\n")  # shadow outer local
 2924     (write _test-input-stream "    out <- copy a\n")  # write to fn output
 2925     (write _test-input-stream "  }\n")
 2926     (write _test-input-stream "  compare a, 0\n")  # use outer local
 2927     (write _test-input-stream "}\n")
 2928     # convert
 2929     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2930     (flush _test-output-buffered-file)
 2931 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2937     # no error; defining 'out' didn't interfere with the reclamation of 'b'
 2938     # check output
 2939     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-fn-output-written-in-inner-block/0")
 2940     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-fn-output-written-in-inner-block/1")
 2941     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-fn-output-written-in-inner-block/2")
 2942     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-fn-output-written-in-inner-block/3")
 2943     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-fn-output-written-in-inner-block/4")
 2944     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-fn-output-written-in-inner-block/5")
 2945     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-fn-output-written-in-inner-block/6")
 2946     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-fn-output-written-in-inner-block/7")
 2947     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-fn-output-written-in-inner-block/8")
 2948     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-fn-output-written-in-inner-block/9")
 2949     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-fn-output-written-in-inner-block/10")
 2950     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-fn-output-written-in-inner-block/10")
 2951     (check-next-stream-line-equal _test-output-stream "      89/<- %edi 0x00000001/r32"  "F - test-fn-output-written-in-inner-block/11")
 2952     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx"  "F - test-fn-output-written-in-inner-block/12")
 2953     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-fn-output-written-in-inner-block/13")
 2954     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-fn-output-written-in-inner-block/14")
 2955     (check-next-stream-line-equal _test-output-stream "    3d/compare-eax-with 0/imm32"  "F - test-fn-output-written-in-inner-block/15")
 2956     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-fn-output-written-in-inner-block/16")
 2957     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-fn-output-written-in-inner-block/17")
 2958     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-fn-output-written-in-inner-block/18")
 2959     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-fn-output-written-in-inner-block/19")
 2960     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-fn-output-written-in-inner-block/20")
 2961     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-fn-output-written-in-inner-block/21")
 2962     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-fn-output-written-in-inner-block/22")
 2963     # . epilogue
 2964     89/<- %esp 5/r32/ebp
 2965     5d/pop-to-ebp
 2966     c3/return
 2967 
 2968 test-convert-function-with-branches-in-block:
 2969     # . prologue
 2970     55/push-ebp
 2971     89/<- %ebp 4/r32/esp
 2972     # setup
 2973     (clear-stream _test-input-stream)
 2974     (clear-stream $_test-input-buffered-file->buffer)
 2975     (clear-stream _test-output-stream)
 2976     (clear-stream $_test-output-buffered-file->buffer)
 2977     #
 2978     (write _test-input-stream "fn foo x: int {\n")
 2979     (write _test-input-stream "  {\n")
 2980     (write _test-input-stream "    break-if->=\n")
 2981     (write _test-input-stream "    loop-if-addr<\n")
 2982     (write _test-input-stream "    increment x\n")
 2983     (write _test-input-stream "    loop\n")
 2984     (write _test-input-stream "  }\n")
 2985     (write _test-input-stream "}\n")
 2986     # convert
 2987     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2988     (flush _test-output-buffered-file)
 2989 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2995     # check output
 2996     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-block/0")
 2997     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-block/1")
 2998     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-block/2")
 2999     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-block/3")
 3000     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-block/4")
 3001     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-block/5")
 3002     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-block/6")
 3003     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-in-block/7")
 3004     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/8")
 3005     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-block/9")
 3006     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-in-block/10")
 3007     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/11")
 3008     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/12")
 3009     (check-next-stream-line-equal _test-output-stream "        0f 83/jump-if-addr>= break/disp32"  "F - test-convert-function-with-branches-in-block/13")
 3010     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:loop/disp32"  "F - test-convert-function-with-branches-in-block/14")
 3011     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/15")
 3012     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-block/16")
 3013     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-in-block/17")
 3014     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-block/18")
 3015     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-in-block/19")
 3016     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-block/20")
 3017     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-block/21")
 3018     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-block/22")
 3019     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-block/23")
 3020     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-block/24")
 3021     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-block/25")
 3022     # . epilogue
 3023     89/<- %esp 5/r32/ebp
 3024     5d/pop-to-ebp
 3025     c3/return
 3026 
 3027 test-convert-function-with-branches-in-named-block:
 3028     # . prologue
 3029     55/push-ebp
 3030     89/<- %ebp 4/r32/esp
 3031     # setup
 3032     (clear-stream _test-input-stream)
 3033     (clear-stream $_test-input-buffered-file->buffer)
 3034     (clear-stream _test-output-stream)
 3035     (clear-stream $_test-output-buffered-file->buffer)
 3036     #
 3037     (write _test-input-stream "fn foo x: int {\n")
 3038     (write _test-input-stream "  $bar: {\n")
 3039     (write _test-input-stream "    break-if->= $bar\n")
 3040     (write _test-input-stream "    loop-if-addr< $bar\n")
 3041     (write _test-input-stream "    increment x\n")
 3042     (write _test-input-stream "    loop\n")
 3043     (write _test-input-stream "  }\n")
 3044     (write _test-input-stream "}\n")
 3045     # convert
 3046     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3047     (flush _test-output-buffered-file)
 3048 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3054     # check output
 3055     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-named-block/0")
 3056     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-named-block/1")
 3057     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-named-block/2")
 3058     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-named-block/3")
 3059     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-named-block/4")
 3060     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-named-block/5")
 3061     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-named-block/6")
 3062     (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-branches-in-named-block/7")
 3063     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-named-block/8")
 3064     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-named-block/9")
 3065     (check-next-stream-line-equal _test-output-stream "        e9/jump $bar:break/disp32"  "F - test-convert-function-with-branches-in-named-block/10")
 3066     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-named-block/11")
 3067     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-named-block/12")
 3068     (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")
 3069     (check-next-stream-line-equal _test-output-stream "        e9/jump $bar:loop/disp32"  "F - test-convert-function-with-branches-in-named-block/14")
 3070     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-named-block/15")
 3071     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-named-block/16")
 3072     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"   "F - test-convert-function-with-branches-in-named-block/17")
 3073     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-named-block/18")
 3074     (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-branches-in-named-block/19")
 3075     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-named-block/20")
 3076     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-named-block/21")
 3077     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-named-block/22")
 3078     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-named-block/23")
 3079     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-named-block/24")
 3080     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-named-block/25")
 3081     # . epilogue
 3082     89/<- %esp 5/r32/ebp
 3083     5d/pop-to-ebp
 3084     c3/return
 3085 
 3086 test-convert-function-with-var-in-nested-block:
 3087     # . prologue
 3088     55/push-ebp
 3089     89/<- %ebp 4/r32/esp
 3090     # setup
 3091     (clear-stream _test-input-stream)
 3092     (clear-stream $_test-input-buffered-file->buffer)
 3093     (clear-stream _test-output-stream)
 3094     (clear-stream $_test-output-buffered-file->buffer)
 3095     #
 3096     (write _test-input-stream "fn foo x: int {\n")
 3097     (write _test-input-stream "  {\n")
 3098     (write _test-input-stream "    {\n")
 3099     (write _test-input-stream "      var x: int\n")
 3100     (write _test-input-stream "      increment x\n")
 3101     (write _test-input-stream "    }\n")
 3102     (write _test-input-stream "  }\n")
 3103     (write _test-input-stream "}\n")
 3104     # convert
 3105     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3106     (flush _test-output-buffered-file)
 3107 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3113     # check output
 3114     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-var-in-nested-block/0")
 3115     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-var-in-nested-block/1")
 3116     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-var-in-nested-block/2")
 3117     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-var-in-nested-block/3")
 3118     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-var-in-nested-block/4")
 3119     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-var-in-nested-block/5")
 3120     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-var-in-nested-block/6")
 3121     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-var-in-nested-block/7")
 3122     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-var-in-nested-block/8")
 3123     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-var-in-nested-block/9")
 3124     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-var-in-nested-block/10")
 3125     (check-next-stream-line-equal _test-output-stream "        ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-var-in-nested-block/11")
 3126     (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")
 3127     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-var-in-nested-block/13")
 3128     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-var-in-nested-block/14")
 3129     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-var-in-nested-block/15")
 3130     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-var-in-nested-block/16")
 3131     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-var-in-nested-block/17")
 3132     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-var-in-nested-block/18")
 3133     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-var-in-nested-block/19")
 3134     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-var-in-nested-block/20")
 3135     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-var-in-nested-block/21")
 3136     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-var-in-nested-block/22")
 3137     # . epilogue
 3138     89/<- %esp 5/r32/ebp
 3139     5d/pop-to-ebp
 3140     c3/return
 3141 
 3142 test-convert-function-with-multiple-vars-in-nested-blocks:
 3143     # . prologue
 3144     55/push-ebp
 3145     89/<- %ebp 4/r32/esp
 3146     # setup
 3147     (clear-stream _test-input-stream)
 3148     (clear-stream $_test-input-buffered-file->buffer)
 3149     (clear-stream _test-output-stream)
 3150     (clear-stream $_test-output-buffered-file->buffer)
 3151     #
 3152     (write _test-input-stream "fn foo x: int {\n")
 3153     (write _test-input-stream "  {\n")
 3154     (write _test-input-stream "    var x/eax: int <- copy 0\n")
 3155     (write _test-input-stream "    {\n")
 3156     (write _test-input-stream "      var y: int\n")
 3157     (write _test-input-stream "      x <- add y\n")
 3158     (write _test-input-stream "    }\n")
 3159     (write _test-input-stream "  }\n")
 3160     (write _test-input-stream "}\n")
 3161     # convert
 3162     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3163     (flush _test-output-buffered-file)
 3164 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3170     # check output
 3171     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-multiple-vars-in-nested-blocks/0")
 3172     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/1")
 3173     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-multiple-vars-in-nested-blocks/2")
 3174     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/3")
 3175     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/4")
 3176     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/5")
 3177     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/6")
 3178     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/7")
 3179     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %eax"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/8")
 3180     (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")
 3181     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/10")
 3182     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/11")
 3183     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-multiple-vars-in-nested-blocks/12")
 3184     (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")
 3185     (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")
 3186     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/15")
 3187     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/16")
 3188     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %eax"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/17")
 3189     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/18")
 3190     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/19")
 3191     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/20")
 3192     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/21")
 3193     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/22")
 3194     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/23")
 3195     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-multiple-vars-in-nested-blocks/24")
 3196     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-multiple-vars-in-nested-blocks/25")
 3197     # . epilogue
 3198     89/<- %esp 5/r32/ebp
 3199     5d/pop-to-ebp
 3200     c3/return
 3201 
 3202 test-convert-function-with-branches-and-local-vars:
 3203     # A conditional 'break' after a 'var' in a block is converted into a
 3204     # nested block that performs all necessary cleanup before jumping. This
 3205     # results in some ugly code duplication.
 3206     # . prologue
 3207     55/push-ebp
 3208     89/<- %ebp 4/r32/esp
 3209     # setup
 3210     (clear-stream _test-input-stream)
 3211     (clear-stream $_test-input-buffered-file->buffer)
 3212     (clear-stream _test-output-stream)
 3213     (clear-stream $_test-output-buffered-file->buffer)
 3214     #
 3215     (write _test-input-stream "fn foo {\n")
 3216     (write _test-input-stream "  {\n")
 3217     (write _test-input-stream "    var x: int\n")
 3218     (write _test-input-stream "    break-if->=\n")
 3219     (write _test-input-stream "    increment x\n")
 3220     (write _test-input-stream "  }\n")
 3221     (write _test-input-stream "}\n")
 3222     # convert
 3223     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3224     (flush _test-output-buffered-file)
 3225 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3231     # check output
 3232     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-local-vars/0")
 3233     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-local-vars/1")
 3234     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-local-vars/2")
 3235     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-and-local-vars/3")
 3236     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-local-vars/4")
 3237     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-local-vars/5")
 3238     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-local-vars/6")
 3239     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-local-vars/7")
 3240     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-local-vars/8")
 3241     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-local-vars/9")
 3242     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-and-local-vars/10")
 3243     (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")
 3244     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-and-local-vars/12")
 3245     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-local-vars/13")
 3246     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-branches-and-local-vars/14")
 3247     (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")
 3248     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-local-vars/16")
 3249     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-local-vars/17")
 3250     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-local-vars/18")
 3251     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-local-vars/19")
 3252     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-local-vars/20")
 3253     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-and-local-vars/21")
 3254     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-local-vars/22")
 3255     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-local-vars/23")
 3256     # . epilogue
 3257     89/<- %esp 5/r32/ebp
 3258     5d/pop-to-ebp
 3259     c3/return
 3260 
 3261 test-convert-function-with-conditional-loops-and-local-vars:
 3262     # A conditional 'loop' after a 'var' in a block is converted into a nested
 3263     # block that performs all necessary cleanup before jumping. This results
 3264     # in some ugly code duplication.
 3265     # . prologue
 3266     55/push-ebp
 3267     89/<- %ebp 4/r32/esp
 3268     # setup
 3269     (clear-stream _test-input-stream)
 3270     (clear-stream $_test-input-buffered-file->buffer)
 3271     (clear-stream _test-output-stream)
 3272     (clear-stream $_test-output-buffered-file->buffer)
 3273     #
 3274     (write _test-input-stream "fn foo {\n")
 3275     (write _test-input-stream "  {\n")
 3276     (write _test-input-stream "    var x: int\n")
 3277     (write _test-input-stream "    loop-if->=\n")
 3278     (write _test-input-stream "    increment x\n")
 3279     (write _test-input-stream "  }\n")
 3280     (write _test-input-stream "}\n")
 3281     # convert
 3282     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3283     (flush _test-output-buffered-file)
 3284 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3290     # check output
 3291     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-conditional-loops-and-local-vars/0")
 3292     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-conditional-loops-and-local-vars/1")
 3293     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-conditional-loops-and-local-vars/2")
 3294     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-conditional-loops-and-local-vars/3")
 3295     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-conditional-loops-and-local-vars/4")
 3296     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/5")
 3297     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-conditional-loops-and-local-vars/6")
 3298     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/7")
 3299     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-conditional-loops-and-local-vars/8")
 3300     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-conditional-loops-and-local-vars/9")
 3301     (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")
 3302     (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")
 3303     (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")
 3304     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-conditional-loops-and-local-vars/13")
 3305     (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")
 3306     (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")
 3307     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-conditional-loops-and-local-vars/16")
 3308     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/17")
 3309     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-conditional-loops-and-local-vars/18")
 3310     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/19")
 3311     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-conditional-loops-and-local-vars/20")
 3312     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-conditional-loops-and-local-vars/21")
 3313     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-conditional-loops-and-local-vars/22")
 3314     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-conditional-loops-and-local-vars/23")
 3315     # . epilogue
 3316     89/<- %esp 5/r32/ebp
 3317     5d/pop-to-ebp
 3318     c3/return
 3319 
 3320 test-convert-function-with-unconditional-loops-and-local-vars:
 3321     # An unconditional 'loop' after a 'var' in a block is emitted _after_ the
 3322     # regular block cleanup. Any instructions after 'loop' are dead and
 3323     # therefore skipped.
 3324     # . prologue
 3325     55/push-ebp
 3326     89/<- %ebp 4/r32/esp
 3327     # setup
 3328     (clear-stream _test-input-stream)
 3329     (clear-stream $_test-input-buffered-file->buffer)
 3330     (clear-stream _test-output-stream)
 3331     (clear-stream $_test-output-buffered-file->buffer)
 3332     #
 3333     (write _test-input-stream "fn foo {\n")
 3334     (write _test-input-stream "  {\n")
 3335     (write _test-input-stream "    var x: int\n")
 3336     (write _test-input-stream "    loop\n")
 3337     (write _test-input-stream "    increment x\n")
 3338     (write _test-input-stream "  }\n")
 3339     (write _test-input-stream "}\n")
 3340     # convert
 3341     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3342     (flush _test-output-buffered-file)
 3343 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3349     # check output
 3350     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-loops-and-local-vars/0")
 3351     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/1")
 3352     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-loops-and-local-vars/2")
 3353     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/3")
 3354     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/4")
 3355     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/5")
 3356     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/6")
 3357     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/7")
 3358     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-loops-and-local-vars/8")
 3359     (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")
 3360     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-unconditional-loops-and-local-vars/10")
 3361     # not emitted:                                           ff 0/subop/increment *(ebp+0xfffffffc)
 3362     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/11")
 3363     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/12")
 3364     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/13")
 3365     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/14")
 3366     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/15")
 3367     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/16")
 3368     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-loops-and-local-vars/17")
 3369     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-loops-and-local-vars/18")
 3370     # . epilogue
 3371     89/<- %esp 5/r32/ebp
 3372     5d/pop-to-ebp
 3373     c3/return
 3374 
 3375 test-convert-function-with-branches-and-loops-and-local-vars:
 3376     # . prologue
 3377     55/push-ebp
 3378     89/<- %ebp 4/r32/esp
 3379     # setup
 3380     (clear-stream _test-input-stream)
 3381     (clear-stream $_test-input-buffered-file->buffer)
 3382     (clear-stream _test-output-stream)
 3383     (clear-stream $_test-output-buffered-file->buffer)
 3384     #
 3385     (write _test-input-stream "fn foo {\n")
 3386     (write _test-input-stream "  {\n")
 3387     (write _test-input-stream "    var x: int\n")
 3388     (write _test-input-stream "    break-if->=\n")
 3389     (write _test-input-stream "    increment x\n")
 3390     (write _test-input-stream "    loop\n")
 3391     (write _test-input-stream "  }\n")
 3392     (write _test-input-stream "}\n")
 3393     # convert
 3394     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3395     (flush _test-output-buffered-file)
 3396 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3402     # check output
 3403     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-loops-and-local-vars/0")
 3404     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/1")
 3405     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-loops-and-local-vars/2")
 3406     (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")
 3407     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/4")
 3408     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/5")
 3409     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/6")
 3410     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/7")
 3411     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-loops-and-local-vars/8")
 3412     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/9")
 3413     (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")
 3414     (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")
 3415     (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")
 3416     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/13")
 3417     (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")
 3418     (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")
 3419     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-and-loops-and-local-vars/16")
 3420     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/17")
 3421     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/18")
 3422     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/19")
 3423     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/20")
 3424     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/21")
 3425     (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")
 3426     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-loops-and-local-vars/23")
 3427     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-loops-and-local-vars/24")
 3428     # . epilogue
 3429     89/<- %esp 5/r32/ebp
 3430     5d/pop-to-ebp
 3431     c3/return
 3432 
 3433 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars:
 3434     # . prologue
 3435     55/push-ebp
 3436     89/<- %ebp 4/r32/esp
 3437     # setup
 3438     (clear-stream _test-input-stream)
 3439     (clear-stream $_test-input-buffered-file->buffer)
 3440     (clear-stream _test-output-stream)
 3441     (clear-stream $_test-output-buffered-file->buffer)
 3442     #
 3443     (write _test-input-stream "fn foo {\n")
 3444     (write _test-input-stream "  a: {\n")
 3445     (write _test-input-stream "    var x: int\n")
 3446     (write _test-input-stream "    {\n")
 3447     (write _test-input-stream "      var y: int\n")
 3448     (write _test-input-stream "      break-if->= a\n")
 3449     (write _test-input-stream "      increment x\n")
 3450     (write _test-input-stream "      loop\n")
 3451     (write _test-input-stream "    }\n")
 3452     (write _test-input-stream "  }\n")
 3453     (write _test-input-stream "}\n")
 3454     # convert
 3455     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3456     (flush _test-output-buffered-file)
 3457 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3463     # check output
 3464     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/0")
 3465     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/1")
 3466     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/2")
 3467     (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")
 3468     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/4")
 3469     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/5")
 3470     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/6")
 3471     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/7")
 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/8")
 3473     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/9")
 3474     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/10")
 3475     (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")
 3476     (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/12")
 3477     (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")
 3478     (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")
 3479     (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")
 3480     (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")
 3481     (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/17")
 3482     (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")
 3483     (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")
 3484     (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")
 3485     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/21")
 3486     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/22")
 3487     (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")
 3488     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/24")
 3489     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/25")
 3490     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/26")
 3491     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/27")
 3492     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/28")
 3493     (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")
 3494     (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")
 3495     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/31")
 3496     # . epilogue
 3497     89/<- %esp 5/r32/ebp
 3498     5d/pop-to-ebp
 3499     c3/return
 3500 
 3501 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2:
 3502     # . prologue
 3503     55/push-ebp
 3504     89/<- %ebp 4/r32/esp
 3505     # setup
 3506     (clear-stream _test-input-stream)
 3507     (clear-stream $_test-input-buffered-file->buffer)
 3508     (clear-stream _test-output-stream)
 3509     (clear-stream $_test-output-buffered-file->buffer)
 3510     # non-local conditional branch from a block without a local variable,
 3511     # unwinding a local on the stack
 3512     (write _test-input-stream "fn foo {\n")
 3513     (write _test-input-stream "  a: {\n")
 3514     (write _test-input-stream "    var x: int\n")
 3515     (write _test-input-stream "    {\n")
 3516     (write _test-input-stream "      break-if->= a\n")
 3517     (write _test-input-stream "    }\n")
 3518     (write _test-input-stream "  }\n")
 3519     (write _test-input-stream "}\n")
 3520     # convert
 3521     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3522     (flush _test-output-buffered-file)
 3523 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3529     # check output
 3530     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/0")
 3531     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/1")
 3532     (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")
 3533     (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")
 3534     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/4")
 3535     (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")
 3536     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/6")
 3537     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/7")
 3538     (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")
 3539     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/9")
 3540     (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")
 3541     (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/11")
 3542     (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")
 3543     (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")
 3544     (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")
 3545     (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/15")
 3546     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/16")
 3547     (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")
 3548     (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")
 3549     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/19")
 3550     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/20")
 3551     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/21")
 3552     (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")
 3553     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/23")
 3554     (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")
 3555     (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")
 3556     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/26")
 3557     # . epilogue
 3558     89/<- %esp 5/r32/ebp
 3559     5d/pop-to-ebp
 3560     c3/return
 3561 
 3562 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3:
 3563     # . prologue
 3564     55/push-ebp
 3565     89/<- %ebp 4/r32/esp
 3566     # setup
 3567     (clear-stream _test-input-stream)
 3568     (clear-stream $_test-input-buffered-file->buffer)
 3569     (clear-stream _test-output-stream)
 3570     (clear-stream $_test-output-buffered-file->buffer)
 3571     # non-local unconditional branch from a block without a local variable,
 3572     # unwinding a local on the stack
 3573     (write _test-input-stream "fn foo {\n")
 3574     (write _test-input-stream "  a: {\n")
 3575     (write _test-input-stream "    var x: int\n")
 3576     (write _test-input-stream "    {\n")
 3577     (write _test-input-stream "      break a\n")
 3578     (write _test-input-stream "    }\n")
 3579     (write _test-input-stream "  }\n")
 3580     (write _test-input-stream "}\n")
 3581     # convert
 3582     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3583     (flush _test-output-buffered-file)
 3584 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3590     # check output
 3591     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/0")
 3592     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/1")
 3593     (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")
 3594     (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")
 3595     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/4")
 3596     (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")
 3597     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/6")
 3598     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/7")
 3599     (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")
 3600     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/9")
 3601     (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")
 3602     (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")
 3603     (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")
 3604     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/14")
 3605     (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")
 3606     (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")
 3607     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/17")
 3608     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/18")
 3609     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/19")
 3610     (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")
 3611     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/21")
 3612     (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")
 3613     (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")
 3614     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/24")
 3615     # . epilogue
 3616     89/<- %esp 5/r32/ebp
 3617     5d/pop-to-ebp
 3618     c3/return
 3619 
 3620 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4:
 3621     # . prologue
 3622     55/push-ebp
 3623     89/<- %ebp 4/r32/esp
 3624     # setup
 3625     (clear-stream _test-input-stream)
 3626     (clear-stream $_test-input-buffered-file->buffer)
 3627     (clear-stream _test-output-stream)
 3628     (clear-stream $_test-output-buffered-file->buffer)
 3629     #
 3630     (write _test-input-stream "fn foo {\n")
 3631     (write _test-input-stream "  a: {\n")
 3632     (write _test-input-stream "    var x/esi: int <- copy 0\n")
 3633     (write _test-input-stream "    {\n")
 3634     (write _test-input-stream "      break a\n")
 3635     (write _test-input-stream "    }\n")
 3636     (write _test-input-stream "  }\n")
 3637     (write _test-input-stream "}\n")
 3638     # convert
 3639     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3640     (flush _test-output-buffered-file)
 3641 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3647     # check output
 3648     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/0")
 3649     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/1")
 3650     (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")
 3651     (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")
 3652     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/4")
 3653     (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")
 3654     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/6")
 3655     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/7")
 3656     (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")
 3657     (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")
 3658     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/10")
 3659     (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")
 3660     (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")
 3661     (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")
 3662     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/14")
 3663     (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")
 3664     (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")
 3665     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/17")
 3666     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/18")
 3667     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/19")
 3668     (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")
 3669     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/21")
 3670     (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")
 3671     (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")
 3672     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/24")
 3673     # . epilogue
 3674     89/<- %esp 5/r32/ebp
 3675     5d/pop-to-ebp
 3676     c3/return
 3677 
 3678 test-convert-function-with-nonlocal-unconditional-break-and-local-vars:
 3679     # . prologue
 3680     55/push-ebp
 3681     89/<- %ebp 4/r32/esp
 3682     # setup
 3683     (clear-stream _test-input-stream)
 3684     (clear-stream $_test-input-buffered-file->buffer)
 3685     (clear-stream _test-output-stream)
 3686     (clear-stream $_test-output-buffered-file->buffer)
 3687     #
 3688     (write _test-input-stream "fn foo {\n")
 3689     (write _test-input-stream "  a: {\n")
 3690     (write _test-input-stream "    var x: int\n")
 3691     (write _test-input-stream "    {\n")
 3692     (write _test-input-stream "      var y: int\n")
 3693     (write _test-input-stream "      break a\n")
 3694     (write _test-input-stream "      increment x\n")
 3695     (write _test-input-stream "    }\n")
 3696     (write _test-input-stream "  }\n")
 3697     (write _test-input-stream "}\n")
 3698     # convert
 3699     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3700     (flush _test-output-buffered-file)
 3701 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3707     # check output
 3708     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/0")
 3709     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/1")
 3710     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/2")
 3711     (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")
 3712     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/4")
 3713     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/5")
 3714     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/6")
 3715     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/7")
 3716     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/8")
 3717     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/9")
 3718     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/10")
 3719     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/11")
 3720     (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")
 3721     (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")
 3722     (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")
 3723     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/15")
 3724     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/16")
 3725     (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")
 3726     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/18")
 3727     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/19")
 3728     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/20")
 3729     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/21")
 3730     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/22")
 3731     (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")
 3732     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/24")
 3733     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/25")
 3734     # . epilogue
 3735     89/<- %esp 5/r32/ebp
 3736     5d/pop-to-ebp
 3737     c3/return
 3738 
 3739 test-convert-function-with-unconditional-break-and-local-vars:
 3740     # . prologue
 3741     55/push-ebp
 3742     89/<- %ebp 4/r32/esp
 3743     # setup
 3744     (clear-stream _test-input-stream)
 3745     (clear-stream $_test-input-buffered-file->buffer)
 3746     (clear-stream _test-output-stream)
 3747     (clear-stream $_test-output-buffered-file->buffer)
 3748     #
 3749     (write _test-input-stream "fn foo {\n")
 3750     (write _test-input-stream "  {\n")
 3751     (write _test-input-stream "    var x: int\n")
 3752     (write _test-input-stream "    {\n")
 3753     (write _test-input-stream "      var y: int\n")
 3754     (write _test-input-stream "      break\n")
 3755     (write _test-input-stream "      increment x\n")
 3756     (write _test-input-stream "    }\n")
 3757     (write _test-input-stream "  }\n")
 3758     (write _test-input-stream "}\n")
 3759     # convert
 3760     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3761     (flush _test-output-buffered-file)
 3762 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3768     # check output
 3769     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-break-and-local-vars/0")
 3770     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-break-and-local-vars/1")
 3771     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-break-and-local-vars/2")
 3772     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-break-and-local-vars/3")
 3773     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-break-and-local-vars/4")
 3774     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/5")
 3775     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-break-and-local-vars/6")
 3776     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/7")
 3777     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-break-and-local-vars/8")
 3778     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-unconditional-break-and-local-vars/9")
 3779     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/10")
 3780     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/11")
 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/12")
 3782     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-unconditional-break-and-local-vars/13")
 3783     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/14")
 3784     (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")
 3785     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-break-and-local-vars/16")
 3786     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/17")
 3787     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-break-and-local-vars/18")
 3788     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/19")
 3789     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-break-and-local-vars/20")
 3790     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-break-and-local-vars/21")
 3791     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-break-and-local-vars/22")
 3792     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-break-and-local-vars/23")
 3793     # . epilogue
 3794     89/<- %esp 5/r32/ebp
 3795     5d/pop-to-ebp
 3796     c3/return
 3797 
 3798 test-convert-function-with-nonlocal-unconditional-loop-and-local-vars:
 3799     # . prologue
 3800     55/push-ebp
 3801     89/<- %ebp 4/r32/esp
 3802     # setup
 3803     (clear-stream _test-input-stream)
 3804     (clear-stream $_test-input-buffered-file->buffer)
 3805     (clear-stream _test-output-stream)
 3806     (clear-stream $_test-output-buffered-file->buffer)
 3807     #
 3808     (write _test-input-stream "fn foo {\n")
 3809     (write _test-input-stream "  a: {\n")
 3810     (write _test-input-stream "    var x: int\n")
 3811     (write _test-input-stream "    {\n")
 3812     (write _test-input-stream "      var y: int\n")
 3813     (write _test-input-stream "      loop a\n")
 3814     (write _test-input-stream "      increment x\n")
 3815     (write _test-input-stream "    }\n")
 3816     (write _test-input-stream "  }\n")
 3817     (write _test-input-stream "}\n")
 3818     # convert
 3819     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3820     (flush _test-output-buffered-file)
 3821 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3827     # check output
 3828     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/0")
 3829     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/1")
 3830     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/2")
 3831     (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")
 3832     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/4")
 3833     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/5")
 3834     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/6")
 3835     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/7")
 3836     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/8")
 3837     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/9")
 3838     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/10")
 3839     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/11")
 3840     (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")
 3841     (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")
 3842     (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")
 3843     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/15")
 3844     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/16")
 3845     (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")
 3846     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/18")
 3847     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/19")
 3848     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/20")
 3849     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/21")
 3850     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/22")
 3851     (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")
 3852     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/24")
 3853     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/25")
 3854     # . epilogue
 3855     89/<- %esp 5/r32/ebp
 3856     5d/pop-to-ebp
 3857     c3/return
 3858 
 3859 test-convert-function-with-local-array-var-in-mem:
 3860     # . prologue
 3861     55/push-ebp
 3862     89/<- %ebp 4/r32/esp
 3863     # setup
 3864     (clear-stream _test-input-stream)
 3865     (clear-stream $_test-input-buffered-file->buffer)
 3866     (clear-stream _test-output-stream)
 3867     (clear-stream $_test-output-buffered-file->buffer)
 3868     #
 3869     (write _test-input-stream "fn foo {\n")
 3870     (write _test-input-stream "  var x: (array int 3)\n")
 3871     (write _test-input-stream "}\n")
 3872     # convert
 3873     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3874     (flush _test-output-buffered-file)
 3875 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3881     # check output
 3882     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-array-var-in-mem/0")
 3883     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-array-var-in-mem/1")
 3884     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-array-var-in-mem/2")
 3885     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-array-var-in-mem/3")
 3886     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-array-var-in-mem/4")
 3887     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-array-var-in-mem/5")
 3888     # define x
 3889     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-function-with-local-array-var-in-mem/7")
 3890     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-function-with-local-array-var-in-mem/8")
 3891     # reclaim x
 3892     (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")
 3893     #
 3894     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-array-var-in-mem/10")
 3895     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-array-var-in-mem/11")
 3896     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-array-var-in-mem/12")
 3897     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-array-var-in-mem/13")
 3898     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-array-var-in-mem/14")
 3899     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-array-var-in-mem/15")
 3900     # . epilogue
 3901     89/<- %esp 5/r32/ebp
 3902     5d/pop-to-ebp
 3903     c3/return
 3904 
 3905 test-array-size-in-hex:
 3906     # . prologue
 3907     55/push-ebp
 3908     89/<- %ebp 4/r32/esp
 3909     # setup
 3910     (clear-stream _test-input-stream)
 3911     (clear-stream $_test-input-buffered-file->buffer)
 3912     (clear-stream _test-output-stream)
 3913     (clear-stream $_test-output-buffered-file->buffer)
 3914     (clear-stream _test-error-stream)
 3915     (clear-stream $_test-error-buffered-file->buffer)
 3916     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 3917     68/push 0/imm32
 3918     68/push 0/imm32
 3919     89/<- %edx 4/r32/esp
 3920     (tailor-exit-descriptor %edx 0x10)
 3921     #
 3922     (write _test-input-stream "fn foo {\n")
 3923     (write _test-input-stream "  var x: (array int 10)\n")
 3924     (write _test-input-stream "}\n")
 3925     # convert
 3926     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 3927     # registers except esp clobbered at this point
 3928     # restore ed
 3929     89/<- %edx 4/r32/esp
 3930     (flush _test-output-buffered-file)
 3931     (flush _test-error-buffered-file)
 3932 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 3938     # check output
 3939     (check-stream-equal _test-output-stream  ""  "F - test-array-size-in-hex: output should be empty")
 3940     (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")
 3941     # check that stop(1) was called
 3942     (check-ints-equal *(edx+4) 2 "F - test-array-size-in-hex: exit status")
 3943     # don't restore from ebp
 3944     81 0/subop/add %esp 8/imm32
 3945     # . epilogue
 3946     5d/pop-to-ebp
 3947     c3/return
 3948 
 3949 test-convert-function-with-populate:
 3950     # . prologue
 3951     55/push-ebp
 3952     89/<- %ebp 4/r32/esp
 3953     # setup
 3954     (clear-stream _test-input-stream)
 3955     (clear-stream $_test-input-buffered-file->buffer)
 3956     (clear-stream _test-output-stream)
 3957     (clear-stream $_test-output-buffered-file->buffer)
 3958     #
 3959     (write _test-input-stream "fn foo {\n")
 3960     (write _test-input-stream "  var x/ecx: (addr handle array int) <- copy 0\n")
 3961     (write _test-input-stream "  populate x, 7\n")
 3962     (write _test-input-stream "}\n")
 3963     # convert
 3964     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3965     (flush _test-output-buffered-file)
 3966 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3972     # check output
 3973     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-populate/0")
 3974     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-populate/1")
 3975     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-populate/2")
 3976     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-populate/3")
 3977     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-populate/4")
 3978     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-populate/5")
 3979     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-populate/6")
 3980     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-populate/7")
 3981     (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)
 3982     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-populate/9")
 3983     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-populate/10")
 3984     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-populate/11")
 3985     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-populate/12")
 3986     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-populate/13")
 3987     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-populate/14")
 3988     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-populate/15")
 3989     # . epilogue
 3990     89/<- %esp 5/r32/ebp
 3991     5d/pop-to-ebp
 3992     c3/return
 3993 
 3994 # special-case for size(byte) when allocating array
 3995 test-convert-function-with-local-array-of-bytes-in-mem:
 3996     # . prologue
 3997     55/push-ebp
 3998     89/<- %ebp 4/r32/esp
 3999     # setup
 4000     (clear-stream _test-input-stream)
 4001     (clear-stream $_test-input-buffered-file->buffer)
 4002     (clear-stream _test-output-stream)
 4003     (clear-stream $_test-output-buffered-file->buffer)
 4004     #
 4005     (write _test-input-stream "fn foo {\n")
 4006     (write _test-input-stream "  var x: (array byte 3)\n")
 4007     (write _test-input-stream "}\n")
 4008     # convert
 4009     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4010     (flush _test-output-buffered-file)
 4011 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4017     # check output
 4018     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-array-of-bytes-in-mem/0")
 4019     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-array-of-bytes-in-mem/1")
 4020     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-array-of-bytes-in-mem/2")
 4021     (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")
 4022     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-array-of-bytes-in-mem/4")
 4023     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-array-of-bytes-in-mem/5")
 4024     # define x
 4025     (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")
 4026     (check-next-stream-line-equal _test-output-stream "    68/push 0x00000003/imm32"  "F - test-convert-function-with-local-array-of-bytes-in-mem/8")
 4027     # reclaim x
 4028     (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")
 4029     #
 4030     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-array-of-bytes-in-mem/10")
 4031     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-array-of-bytes-in-mem/11")
 4032     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-array-of-bytes-in-mem/12")
 4033     (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")
 4034     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-array-of-bytes-in-mem/14")
 4035     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-array-of-bytes-in-mem/15")
 4036     # . epilogue
 4037     89/<- %esp 5/r32/ebp
 4038     5d/pop-to-ebp
 4039     c3/return
 4040 
 4041 test-convert-address:
 4042     # . prologue
 4043     55/push-ebp
 4044     89/<- %ebp 4/r32/esp
 4045     # setup
 4046     (clear-stream _test-input-stream)
 4047     (clear-stream $_test-input-buffered-file->buffer)
 4048     (clear-stream _test-output-stream)
 4049     (clear-stream $_test-output-buffered-file->buffer)
 4050     #
 4051     (write _test-input-stream "fn foo {\n")
 4052     (write _test-input-stream "  var a: int\n")
 4053     (write _test-input-stream "  var b/eax: (addr int) <- address a\n")
 4054     (write _test-input-stream "}\n")
 4055     # convert
 4056     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4057     (flush _test-output-buffered-file)
 4058 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4064     # check output
 4065     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-address/0")
 4066     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-address/1")
 4067     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-address/2")
 4068     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-address/3")
 4069     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-address/4")
 4070     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-address/5")
 4071     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-address/6")
 4072     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-address/7")
 4073     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000000/r32"  "F - test-convert-address/8")
 4074     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-address/9")
 4075     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-address/10")
 4076     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-address/11")
 4077     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-address/12")
 4078     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-address/13")
 4079     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-address/14")
 4080     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-address/15")
 4081     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-address/16")
 4082     # . epilogue
 4083     89/<- %esp 5/r32/ebp
 4084     5d/pop-to-ebp
 4085     c3/return
 4086 
 4087 test-convert-length-of-array:
 4088     # . prologue
 4089     55/push-ebp
 4090     89/<- %ebp 4/r32/esp
 4091     # setup
 4092     (clear-stream _test-input-stream)
 4093     (clear-stream $_test-input-buffered-file->buffer)
 4094     (clear-stream _test-output-stream)
 4095     (clear-stream $_test-output-buffered-file->buffer)
 4096     #
 4097     (write _test-input-stream "fn foo a: (addr array int) {\n")
 4098     (write _test-input-stream "  var b/eax: (addr array int) <- copy a\n")
 4099     (write _test-input-stream "  var c/eax: int <- length b\n")
 4100     (write _test-input-stream "}\n")
 4101     # convert
 4102     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4103     (flush _test-output-buffered-file)
 4104 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4110     # check output
 4111     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array/0")
 4112     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array/1")
 4113     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array/2")
 4114     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array/3")
 4115     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array/4")
 4116     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array/5")
 4117     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array/6")
 4118     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-length-of-array/7")
 4119     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array/8")
 4120     (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array/9")
 4121     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array/10")
 4122     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array/11")
 4123     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array/12")
 4124     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array/13")
 4125     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array/14")
 4126     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array/15")
 4127     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array/16")
 4128     # . epilogue
 4129     89/<- %esp 5/r32/ebp
 4130     5d/pop-to-ebp
 4131     c3/return
 4132 
 4133 # special-case for size(byte) when computing array length
 4134 test-convert-length-of-array-of-bytes:
 4135     # . prologue
 4136     55/push-ebp
 4137     89/<- %ebp 4/r32/esp
 4138     # setup
 4139     (clear-stream _test-input-stream)
 4140     (clear-stream $_test-input-buffered-file->buffer)
 4141     (clear-stream _test-output-stream)
 4142     (clear-stream $_test-output-buffered-file->buffer)
 4143     #
 4144     (write _test-input-stream "fn foo a: (addr array byte) {\n")
 4145     (write _test-input-stream "  var b/eax: (addr array byte) <- copy a\n")
 4146     (write _test-input-stream "  var c/eax: int <- length b\n")
 4147     (write _test-input-stream "}\n")
 4148     # convert
 4149     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4150     (flush _test-output-buffered-file)
 4151 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4157     # check output
 4158     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-bytes/0")
 4159     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-bytes/1")
 4160     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-bytes/2")
 4161     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-bytes/3")
 4162     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-bytes/4")
 4163     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-bytes/5")
 4164     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-bytes/6")
 4165     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-length-of-array-of-bytes/7")
 4166     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-bytes/8")
 4167     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-bytes/9")
 4168     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-bytes/10")
 4169     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-bytes/11")
 4170     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-bytes/12")
 4171     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-bytes/13")
 4172     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-bytes/14")
 4173     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-bytes/15")
 4174     # . epilogue
 4175     89/<- %esp 5/r32/ebp
 4176     5d/pop-to-ebp
 4177     c3/return
 4178 
 4179 test-convert-length-of-array-on-stack:
 4180     # . prologue
 4181     55/push-ebp
 4182     89/<- %ebp 4/r32/esp
 4183     # setup
 4184     (clear-stream _test-input-stream)
 4185     (clear-stream $_test-input-buffered-file->buffer)
 4186     (clear-stream _test-output-stream)
 4187     (clear-stream $_test-output-buffered-file->buffer)
 4188     #
 4189     (write _test-input-stream "fn foo {\n")
 4190     (write _test-input-stream "  var a: (array int 3)\n")
 4191     (write _test-input-stream "  var b/eax: int <- length a\n")
 4192     (write _test-input-stream "}\n")
 4193     # convert
 4194     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4195     (flush _test-output-buffered-file)
 4196 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4202     # check output
 4203     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-on-stack/0")
 4204     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-on-stack/1")
 4205     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-on-stack/2")
 4206     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-on-stack/3")
 4207     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-on-stack/4")
 4208     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-on-stack/5")
 4209     # define x
 4210     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-length-of-array-on-stack/6")
 4211     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-length-of-array-on-stack/7")
 4212     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-on-stack/8")
 4213     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0xfffffff0) 0x00000000/r32"  "F - test-convert-length-of-array-on-stack/9")
 4214     (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array-on-stack/10")
 4215     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-on-stack/11")
 4216     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"  "F - test-convert-length-of-array-on-stack/12")
 4217     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-on-stack/13")
 4218     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-on-stack/14")
 4219     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-on-stack/15")
 4220     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-on-stack/16")
 4221     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-on-stack/17")
 4222     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-on-stack/18")
 4223     # . epilogue
 4224     89/<- %esp 5/r32/ebp
 4225     5d/pop-to-ebp
 4226     c3/return
 4227 
 4228 test-reg-var-def-with-read-of-same-register:
 4229     # . prologue
 4230     55/push-ebp
 4231     89/<- %ebp 4/r32/esp
 4232     # setup
 4233     (clear-stream _test-input-stream)
 4234     (clear-stream $_test-input-buffered-file->buffer)
 4235     (clear-stream _test-output-stream)
 4236     (clear-stream $_test-output-buffered-file->buffer)
 4237     (clear-stream _test-error-stream)
 4238     (clear-stream $_test-error-buffered-file->buffer)
 4239     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)  # bytes of args in call to convert-mu
 4240     68/push 0/imm32
 4241     68/push 0/imm32
 4242     89/<- %edx 4/r32/esp
 4243     (tailor-exit-descriptor %edx 0x10)
 4244     #
 4245     (write _test-input-stream "fn foo {\n")
 4246     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4247     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4248     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 4249     (write _test-input-stream "}\n")
 4250     # convert
 4251     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 4252     # registers except esp could be clobbered at this point (though they shouldn't be)
 4253     # restore ed
 4254     89/<- %edx 4/r32/esp
 4255     (flush _test-output-buffered-file)
 4256     (flush _test-error-buffered-file)
 4257 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4263     (check-stream-equal _test-error-stream  ""  "F - test-reg-var-def-with-read-of-same-register: error stream should be empty")
 4264     # check output
 4265     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-reg-var-def-with-read-of-same-register/0")
 4266     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-reg-var-def-with-read-of-same-register/1")
 4267     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-reg-var-def-with-read-of-same-register/2")
 4268     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-reg-var-def-with-read-of-same-register/3")
 4269     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-reg-var-def-with-read-of-same-register/4")
 4270     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-reg-var-def-with-read-of-same-register/5")
 4271     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-reg-var-def-with-read-of-same-register/6")
 4272     (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")
 4273     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-reg-var-def-with-read-of-same-register/8")
 4274     (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")
 4275     (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")
 4276     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-reg-var-def-with-read-of-same-register/13")
 4277     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-reg-var-def-with-read-of-same-register/14")
 4278     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-reg-var-def-with-read-of-same-register/15")
 4279     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-reg-var-def-with-read-of-same-register/16")
 4280     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-reg-var-def-with-read-of-same-register/17")
 4281     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-reg-var-def-with-read-of-same-register/18")
 4282     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-reg-var-def-with-read-of-same-register/19")
 4283     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-reg-var-def-with-read-of-same-register/20")
 4284     # don't restore from ebp
 4285     81 0/subop/add %esp 8/imm32
 4286     # . epilogue
 4287     5d/pop-to-ebp
 4288     c3/return
 4289 
 4290 test-convert-index-into-array:
 4291     # . prologue
 4292     55/push-ebp
 4293     89/<- %ebp 4/r32/esp
 4294     # setup
 4295     (clear-stream _test-input-stream)
 4296     (clear-stream $_test-input-buffered-file->buffer)
 4297     (clear-stream _test-output-stream)
 4298     (clear-stream $_test-output-buffered-file->buffer)
 4299     #
 4300     (write _test-input-stream "fn foo {\n")
 4301     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4302     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4303     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 4304     (write _test-input-stream "}\n")
 4305     # convert
 4306     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4307     (flush _test-output-buffered-file)
 4308 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4314     # check output
 4315     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array/0")
 4316     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array/1")
 4317     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array/2")
 4318     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array/3")
 4319     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array/4")
 4320     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array/5")
 4321     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array/6")
 4322     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array/7")
 4323     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array/8")
 4324     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array/9")
 4325     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx<<0x00000002 + 4) 0x00000000/r32"  "F - test-convert-index-into-array/10")
 4326     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array/11")
 4327     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array/12")
 4328     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array/13")
 4329     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array/14")
 4330     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array/15")
 4331     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array/16")
 4332     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array/17")
 4333     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array/18")
 4334     # . epilogue
 4335     89/<- %esp 5/r32/ebp
 4336     5d/pop-to-ebp
 4337     c3/return
 4338 
 4339 test-convert-index-into-array-of-bytes:
 4340     # . prologue
 4341     55/push-ebp
 4342     89/<- %ebp 4/r32/esp
 4343     # setup
 4344     (clear-stream _test-input-stream)
 4345     (clear-stream $_test-input-buffered-file->buffer)
 4346     (clear-stream _test-output-stream)
 4347     (clear-stream $_test-output-buffered-file->buffer)
 4348     #
 4349     (write _test-input-stream "fn foo {\n")
 4350     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4351     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4352     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, idx\n")
 4353     (write _test-input-stream "}\n")
 4354     # convert
 4355     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4356     (flush _test-output-buffered-file)
 4357 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4363     # check output
 4364     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes/0")
 4365     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes/1")
 4366     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes/2")
 4367     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes/3")
 4368     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes/4")
 4369     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes/5")
 4370     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes/6")
 4371     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-of-bytes/7")
 4372     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes/8")
 4373     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-of-bytes/9")
 4374     (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")
 4375     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes/13")
 4376     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes/14")
 4377     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes/15")
 4378     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes/16")
 4379     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes/17")
 4380     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes/18")
 4381     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes/19")
 4382     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes/20")
 4383     # . epilogue
 4384     89/<- %esp 5/r32/ebp
 4385     5d/pop-to-ebp
 4386     c3/return
 4387 
 4388 test-convert-index-into-array-with-literal:
 4389     # . prologue
 4390     55/push-ebp
 4391     89/<- %ebp 4/r32/esp
 4392     # setup
 4393     (clear-stream _test-input-stream)
 4394     (clear-stream $_test-input-buffered-file->buffer)
 4395     (clear-stream _test-output-stream)
 4396     (clear-stream $_test-output-buffered-file->buffer)
 4397     #
 4398     (write _test-input-stream "fn foo {\n")
 4399     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4400     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
 4401     (write _test-input-stream "}\n")
 4402     # convert
 4403     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4404     (flush _test-output-buffered-file)
 4405 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4411     # check output
 4412     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-with-literal/0")
 4413     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-with-literal/1")
 4414     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-with-literal/2")
 4415     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-with-literal/3")
 4416     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-with-literal/4")
 4417     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-with-literal/5")
 4418     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-with-literal/6")
 4419     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-with-literal/7")
 4420                                                                                  # 2 * 4 bytes/elem + 4 bytes for size = offset 12
 4421     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x0000000c) 0x00000000/r32"  "F - test-convert-index-into-array-with-literal/8")
 4422     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-with-literal/9")
 4423     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-with-literal/10")
 4424     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-with-literal/11")
 4425     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-with-literal/12")
 4426     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-with-literal/13")
 4427     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-with-literal/14")
 4428     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-with-literal/15")
 4429     # . epilogue
 4430     89/<- %esp 5/r32/ebp
 4431     5d/pop-to-ebp
 4432     c3/return
 4433 
 4434 test-convert-index-into-array-of-bytes-with-literal:
 4435     # . prologue
 4436     55/push-ebp
 4437     89/<- %ebp 4/r32/esp
 4438     # setup
 4439     (clear-stream _test-input-stream)
 4440     (clear-stream $_test-input-buffered-file->buffer)
 4441     (clear-stream _test-output-stream)
 4442     (clear-stream $_test-output-buffered-file->buffer)
 4443     #
 4444     (write _test-input-stream "fn foo {\n")
 4445     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4446     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, 2\n")
 4447     (write _test-input-stream "}\n")
 4448     # convert
 4449     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4450     (flush _test-output-buffered-file)
 4451 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4457     # check output
 4458     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-with-literal/0")
 4459     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-with-literal/1")
 4460     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-with-literal/2")
 4461     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-with-literal/3")
 4462     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-with-literal/4")
 4463     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-with-literal/5")
 4464     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-with-literal/6")
 4465     (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")
 4466                                                                                  # 2 * 1 byte/elem + 4 bytes for size = offset 6
 4467     (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")
 4468     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-with-literal/9")
 4469     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-with-literal/10")
 4470     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-with-literal/11")
 4471     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-with-literal/12")
 4472     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-with-literal/13")
 4473     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-with-literal/14")
 4474     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-with-literal/15")
 4475     # . epilogue
 4476     89/<- %esp 5/r32/ebp
 4477     5d/pop-to-ebp
 4478     c3/return
 4479 
 4480 test-convert-index-into-array-on-stack:
 4481     # . prologue
 4482     55/push-ebp
 4483     89/<- %ebp 4/r32/esp
 4484     # setup
 4485     (clear-stream _test-input-stream)
 4486     (clear-stream $_test-input-buffered-file->buffer)
 4487     (clear-stream _test-output-stream)
 4488     (clear-stream $_test-output-buffered-file->buffer)
 4489     #
 4490     (write _test-input-stream "fn foo {\n")
 4491     (write _test-input-stream "  var arr: (array int 3)\n")
 4492     (write _test-input-stream "  var idx/eax: int <- copy 2\n")
 4493     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 4494     (write _test-input-stream "}\n")
 4495     # convert
 4496     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4497     (flush _test-output-buffered-file)
 4498 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4504     # check output
 4505     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack/0")
 4506     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack/1")
 4507     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack/2")
 4508     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack/3")
 4509     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack/4")
 4510     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack/5")
 4511     # var arr
 4512     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack/6")
 4513     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack/7")
 4514     # var idx
 4515     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack/8")
 4516     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 2/imm32"                  "F - test-convert-index-into-array-on-stack/9")
 4517     # var x is at (ebp-0x10) + idx<<2 + 4 = ebp + idx<<2 - 0xc
 4518     (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")
 4519     # reclaim idx
 4520     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack/11")
 4521     # reclaim arr
 4522     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"    "F - test-convert-index-into-array-on-stack/12")
 4523     #
 4524     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack/13")
 4525     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack/14")
 4526     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack/15")
 4527     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack/16")
 4528     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack/17")
 4529     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack/18")
 4530     # . epilogue
 4531     89/<- %esp 5/r32/ebp
 4532     5d/pop-to-ebp
 4533     c3/return
 4534 
 4535 test-convert-index-into-array-on-stack-with-literal:
 4536     # . prologue
 4537     55/push-ebp
 4538     89/<- %ebp 4/r32/esp
 4539     # setup
 4540     (clear-stream _test-input-stream)
 4541     (clear-stream $_test-input-buffered-file->buffer)
 4542     (clear-stream _test-output-stream)
 4543     (clear-stream $_test-output-buffered-file->buffer)
 4544     #
 4545     (write _test-input-stream "fn foo {\n")
 4546     (write _test-input-stream "  var arr: (array int 3)\n")
 4547     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
 4548     (write _test-input-stream "}\n")
 4549     # convert
 4550     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4551     (flush _test-output-buffered-file)
 4552 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4558     # check output
 4559     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack-with-literal/0")
 4560     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack-with-literal/1")
 4561     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack-with-literal/2")
 4562     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack-with-literal/3")
 4563     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack-with-literal/4")
 4564     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack-with-literal/5")
 4565     # var arr
 4566     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack-with-literal/6")
 4567     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack-with-literal/7")
 4568     # var x
 4569     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack-with-literal/8")
 4570     # x is at (ebp-0x10) + 4 + 2*4 = ebp-4
 4571     (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")
 4572     # reclaim x
 4573     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack-with-literal/10")
 4574     # reclaim arr
 4575     (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")
 4576     #
 4577     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack-with-literal/12")
 4578     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack-with-literal/13")
 4579     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack-with-literal/14")
 4580     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack-with-literal/15")
 4581     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack-with-literal/16")
 4582     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack-with-literal/17")
 4583     # . epilogue
 4584     89/<- %esp 5/r32/ebp
 4585     5d/pop-to-ebp
 4586     c3/return
 4587 
 4588 test-convert-index-into-array-of-bytes-on-stack-with-literal:
 4589     # . prologue
 4590     55/push-ebp
 4591     89/<- %ebp 4/r32/esp
 4592     # setup
 4593     (clear-stream _test-input-stream)
 4594     (clear-stream $_test-input-buffered-file->buffer)
 4595     (clear-stream _test-output-stream)
 4596     (clear-stream $_test-output-buffered-file->buffer)
 4597     #
 4598     (write _test-input-stream "fn foo {\n")
 4599     (write _test-input-stream "  var arr: (array byte 3)\n")
 4600     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, 2\n")
 4601     (write _test-input-stream "}\n")
 4602     # convert
 4603     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4604     (flush _test-output-buffered-file)
 4605 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4611     # check output
 4612     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/0")
 4613     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/1")
 4614     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/2")
 4615     (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")
 4616     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/4")
 4617     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/5")
 4618     # var arr
 4619     (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")
 4620     (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")
 4621     # var x
 4622     (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")
 4623     # x is at (ebp-7) + 4 + 2 = ebp-1
 4624     (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")
 4625     # reclaim x
 4626     (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")
 4627     # reclaim arr
 4628     (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")
 4629     #
 4630     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/12")
 4631     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/13")
 4632     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/14")
 4633     (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")
 4634     (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")
 4635     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/17")
 4636     # . epilogue
 4637     89/<- %esp 5/r32/ebp
 4638     5d/pop-to-ebp
 4639     c3/return
 4640 
 4641 test-convert-index-into-array-using-offset:
 4642     # . prologue
 4643     55/push-ebp
 4644     89/<- %ebp 4/r32/esp
 4645     # setup
 4646     (clear-stream _test-input-stream)
 4647     (clear-stream $_test-input-buffered-file->buffer)
 4648     (clear-stream _test-output-stream)
 4649     (clear-stream $_test-output-buffered-file->buffer)
 4650     #
 4651     (write _test-input-stream "fn foo {\n")
 4652     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4653     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4654     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
 4655     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
 4656     (write _test-input-stream "}\n")
 4657     # convert
 4658     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4659     (flush _test-output-buffered-file)
 4660 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4666     # check output
 4667     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset/0")
 4668     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset/1")
 4669     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset/2")
 4670     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset/3")
 4671     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset/4")
 4672     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset/5")
 4673     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset/6")
 4674     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-using-offset/7")
 4675     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset/8")
 4676     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-using-offset/9")
 4677     (check-next-stream-line-equal _test-output-stream "    69/multiply %ecx 0x00000004/imm32 0x00000001/r32"  "F - test-convert-index-into-array-using-offset/10")
 4678     (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")
 4679     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset/12")
 4680     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset/13")
 4681     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset/14")
 4682     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset/15")
 4683     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset/16")
 4684     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset/17")
 4685     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset/18")
 4686     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset/19")
 4687     # . epilogue
 4688     89/<- %esp 5/r32/ebp
 4689     5d/pop-to-ebp
 4690     c3/return
 4691 
 4692 test-convert-index-into-array-of-bytes-using-offset:
 4693     # . prologue
 4694     55/push-ebp
 4695     89/<- %ebp 4/r32/esp
 4696     # setup
 4697     (clear-stream _test-input-stream)
 4698     (clear-stream $_test-input-buffered-file->buffer)
 4699     (clear-stream _test-output-stream)
 4700     (clear-stream $_test-output-buffered-file->buffer)
 4701     #
 4702     (write _test-input-stream "fn foo {\n")
 4703     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4704     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4705     (write _test-input-stream "  var off/ecx: (offset byte) <- compute-offset arr, idx\n")
 4706     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, off\n")
 4707     (write _test-input-stream "}\n")
 4708     # convert
 4709     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4710     (flush _test-output-buffered-file)
 4711 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4717     # check output
 4718     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-using-offset/0")
 4719     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-using-offset/1")
 4720     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-using-offset/2")
 4721     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-using-offset/3")
 4722     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-using-offset/4")
 4723     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-using-offset/5")
 4724     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-using-offset/6")
 4725     (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")
 4726     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes-using-offset/8")
 4727     (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")
 4728     (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")
 4729     (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")
 4730     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes-using-offset/12")
 4731     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-using-offset/13")
 4732     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-using-offset/14")
 4733     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-using-offset/15")
 4734     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-using-offset/16")
 4735     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-using-offset/17")
 4736     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-using-offset/18")
 4737     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-using-offset/19")
 4738     # . epilogue
 4739     89/<- %esp 5/r32/ebp
 4740     5d/pop-to-ebp
 4741     c3/return
 4742 
 4743 test-convert-index-into-array-using-offset-on-stack:
 4744     # . prologue
 4745     55/push-ebp
 4746     89/<- %ebp 4/r32/esp
 4747     # setup
 4748     (clear-stream _test-input-stream)
 4749     (clear-stream $_test-input-buffered-file->buffer)
 4750     (clear-stream _test-output-stream)
 4751     (clear-stream $_test-output-buffered-file->buffer)
 4752     #
 4753     (write _test-input-stream "fn foo {\n")
 4754     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4755     (write _test-input-stream "  var idx: int\n")
 4756     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
 4757     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
 4758     (write _test-input-stream "}\n")
 4759     # convert
 4760     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4761     (flush _test-output-buffered-file)
 4762 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4768     # check output
 4769     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset-on-stack/0")
 4770     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset-on-stack/1")
 4771     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset-on-stack/2")
 4772     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset-on-stack/3")
 4773     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset-on-stack/4")
 4774     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset-on-stack/5")
 4775     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset-on-stack/6")
 4776     (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")
 4777     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"                         "F - test-convert-index-into-array-using-offset-on-stack/8")
 4778     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset-on-stack/9")
 4779     (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")
 4780     (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")
 4781     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset-on-stack/12")
 4782     (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")
 4783     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset-on-stack/14")
 4784     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset-on-stack/15")
 4785     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset-on-stack/16")
 4786     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset-on-stack/17")
 4787     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset-on-stack/18")
 4788     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset-on-stack/19")
 4789     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset-on-stack/20")
 4790     # . epilogue
 4791     89/<- %esp 5/r32/ebp
 4792     5d/pop-to-ebp
 4793     c3/return
 4794 
 4795 test-convert-index-into-array-of-bytes-using-offset-on-stack:
 4796     # . prologue
 4797     55/push-ebp
 4798     89/<- %ebp 4/r32/esp
 4799     # setup
 4800     (clear-stream _test-input-stream)
 4801     (clear-stream $_test-input-buffered-file->buffer)
 4802     (clear-stream _test-output-stream)
 4803     (clear-stream $_test-output-buffered-file->buffer)
 4804     #
 4805     (write _test-input-stream "fn foo {\n")
 4806     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4807     (write _test-input-stream "  var idx: int\n")
 4808     (write _test-input-stream "  var off/ecx: (offset byte) <- compute-offset arr, idx\n")
 4809     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, off\n")
 4810     (write _test-input-stream "}\n")
 4811     # convert
 4812     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4813     (flush _test-output-buffered-file)
 4814 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4820     # check output
 4821     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/0")
 4822     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/1")
 4823     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/2")
 4824     (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")
 4825     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/4")
 4826     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/5")
 4827     (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")
 4828     (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")
 4829     (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")
 4830     (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")
 4831     (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")
 4832     (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")
 4833     (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")
 4834     (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")
 4835     (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")
 4836     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/15")
 4837     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/16")
 4838     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/17")
 4839     (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")
 4840     (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")
 4841     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/20")
 4842     # . epilogue
 4843     89/<- %esp 5/r32/ebp
 4844     5d/pop-to-ebp
 4845     c3/return
 4846 
 4847 test-convert-function-and-type-definition:
 4848     # . prologue
 4849     55/push-ebp
 4850     89/<- %ebp 4/r32/esp
 4851     # setup
 4852     (clear-stream _test-input-stream)
 4853     (clear-stream $_test-input-buffered-file->buffer)
 4854     (clear-stream _test-output-stream)
 4855     (clear-stream $_test-output-buffered-file->buffer)
 4856     #
 4857     (write _test-input-stream "fn foo a: (addr t) {\n")
 4858     (write _test-input-stream "  var _a/eax: (addr t) <- copy a\n")
 4859     (write _test-input-stream "  var b/ecx: (addr int) <- get _a, x\n")
 4860     (write _test-input-stream "  var c/ecx: (addr int) <- get _a, y\n")
 4861     (write _test-input-stream "}\n")
 4862     (write _test-input-stream "type t {\n")
 4863     (write _test-input-stream "  x: int\n")
 4864     (write _test-input-stream "  y: int\n")
 4865     (write _test-input-stream "}\n")
 4866     # convert
 4867     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4868     (flush _test-output-buffered-file)
 4869 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4875     # check output
 4876     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-and-type-definition/0")
 4877     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-and-type-definition/1")
 4878     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-and-type-definition/2")
 4879     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-and-type-definition/3")
 4880     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-and-type-definition/4")
 4881     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-and-type-definition/5")
 4882     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-function-and-type-definition/6")
 4883     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-and-type-definition/7")
 4884     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-and-type-definition/8")
 4885     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000000) 0x00000001/r32"  "F - test-convert-function-and-type-definition/9")
 4886     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000004) 0x00000001/r32"  "F - test-convert-function-and-type-definition/11")
 4887     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-and-type-definition/13")
 4888     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-convert-function-and-type-definition/14")
 4889     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-and-type-definition/15")
 4890     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-and-type-definition/16")
 4891     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-and-type-definition/17")
 4892     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-and-type-definition/18")
 4893     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-and-type-definition/19")
 4894     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-and-type-definition/20")
 4895     # . epilogue
 4896     89/<- %esp 5/r32/ebp
 4897     5d/pop-to-ebp
 4898     c3/return
 4899 
 4900 test-type-definition-with-array:
 4901     # . prologue
 4902     55/push-ebp
 4903     89/<- %ebp 4/r32/esp
 4904     # setup
 4905     (clear-stream _test-input-stream)
 4906     (clear-stream $_test-input-buffered-file->buffer)
 4907     (clear-stream _test-output-stream)
 4908     (clear-stream $_test-output-buffered-file->buffer)
 4909     (clear-stream _test-error-stream)
 4910     (clear-stream $_test-error-buffered-file->buffer)
 4911     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 4912     68/push 0/imm32
 4913     68/push 0/imm32
 4914     89/<- %edx 4/r32/esp
 4915     (tailor-exit-descriptor %edx 0x10)
 4916     #
 4917     (write _test-input-stream "type t {\n")
 4918     (write _test-input-stream "  a: (array int 3)\n")
 4919     (write _test-input-stream "}\n")
 4920     # convert
 4921     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 4922     # registers except esp clobbered at this point
 4923     # restore ed
 4924     89/<- %edx 4/r32/esp
 4925     (flush _test-output-buffered-file)
 4926     (flush _test-error-buffered-file)
 4927 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 4933     # check output
 4934     (check-stream-equal _test-output-stream  ""  "F - test-type-definition-with-array: output should be empty")
 4935     (check-next-stream-line-equal _test-error-stream  "type t: 'array' elements not allowed for now"  "F - test-type-definition-with-array: error message")
 4936     # check that stop(1) was called
 4937     (check-ints-equal *(edx+4) 2 "F - test-type-definition-with-array: exit status")
 4938     # don't restore from ebp
 4939     81 0/subop/add %esp 8/imm32
 4940     # . epilogue
 4941     5d/pop-to-ebp
 4942     c3/return
 4943 
 4944 test-type-definition-with-addr:
 4945     # . prologue
 4946     55/push-ebp
 4947     89/<- %ebp 4/r32/esp
 4948     # setup
 4949     (clear-stream _test-input-stream)
 4950     (clear-stream $_test-input-buffered-file->buffer)
 4951     (clear-stream _test-output-stream)
 4952     (clear-stream $_test-output-buffered-file->buffer)
 4953     (clear-stream _test-error-stream)
 4954     (clear-stream $_test-error-buffered-file->buffer)
 4955     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 4956     68/push 0/imm32
 4957     68/push 0/imm32
 4958     89/<- %edx 4/r32/esp
 4959     (tailor-exit-descriptor %edx 0x10)
 4960     #
 4961     (write _test-input-stream "type t {\n")
 4962     (write _test-input-stream "  a: (addr int)\n")
 4963     (write _test-input-stream "}\n")
 4964     # convert
 4965     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 4966     # registers except esp clobbered at this point
 4967     # restore ed
 4968     89/<- %edx 4/r32/esp
 4969     (flush _test-output-buffered-file)
 4970     (flush _test-error-buffered-file)
 4971 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 4977     # check output
 4978     (check-stream-equal _test-output-stream  ""  "F - test-type-definition-with-addr: output should be empty")
 4979     (check-next-stream-line-equal _test-error-stream  "type t: 'addr' elements not allowed"  "F - test-type-definition-with-addr: error message")
 4980     # check that stop(1) was called
 4981     (check-ints-equal *(edx+4) 2 "F - test-type-definition-with-addr: exit status")
 4982     # don't restore from ebp
 4983     81 0/subop/add %esp 8/imm32
 4984     # . epilogue
 4985     5d/pop-to-ebp
 4986     c3/return
 4987 
 4988 test-convert-function-with-local-var-with-user-defined-type:
 4989     # . prologue
 4990     55/push-ebp
 4991     89/<- %ebp 4/r32/esp
 4992     # setup
 4993     (clear-stream _test-input-stream)
 4994     (clear-stream $_test-input-buffered-file->buffer)
 4995     (clear-stream _test-output-stream)
 4996     (clear-stream $_test-output-buffered-file->buffer)
 4997     #
 4998     (write _test-input-stream "fn foo {\n")
 4999     (write _test-input-stream "  var a: t\n")
 5000     (write _test-input-stream "}\n")
 5001     (write _test-input-stream "type t {\n")
 5002     (write _test-input-stream "  x: int\n")
 5003     (write _test-input-stream "  y: int\n")
 5004     (write _test-input-stream "}\n")
 5005     # convert
 5006     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5007     (flush _test-output-buffered-file)
 5008 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5014     # check output
 5015     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-user-defined-type/0")
 5016     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-user-defined-type/1")
 5017     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-user-defined-type/2")
 5018     (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")
 5019     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-user-defined-type/4")
 5020     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-user-defined-type/5")
 5021     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/6")
 5022     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/7")
 5023     (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")
 5024     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-user-defined-type/9")
 5025     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-user-defined-type/10")
 5026     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-user-defined-type/11")
 5027     (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")
 5028     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-with-user-defined-type/13")
 5029     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-user-defined-type/14")
 5030     # . epilogue
 5031     89/<- %esp 5/r32/ebp
 5032     5d/pop-to-ebp
 5033     c3/return
 5034 
 5035 test-convert-function-call-with-arg-of-user-defined-type:
 5036     # . prologue
 5037     55/push-ebp
 5038     89/<- %ebp 4/r32/esp
 5039     # setup
 5040     (clear-stream _test-input-stream)
 5041     (clear-stream $_test-input-buffered-file->buffer)
 5042     (clear-stream _test-output-stream)
 5043     (clear-stream $_test-output-buffered-file->buffer)
 5044     #
 5045     (write _test-input-stream "fn f {\n")
 5046     (write _test-input-stream "  var a: t\n")
 5047     (write _test-input-stream "  foo a\n")
 5048     (write _test-input-stream "}\n")
 5049     (write _test-input-stream "fn foo x: t {\n")
 5050     (write _test-input-stream "}\n")
 5051     (write _test-input-stream "type t {\n")
 5052     (write _test-input-stream "  x: int\n")
 5053     (write _test-input-stream "  y: int\n")
 5054     (write _test-input-stream "}\n")
 5055     # convert
 5056     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5057     (flush _test-output-buffered-file)
 5058 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5064     # check output
 5065     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
 5066     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
 5067     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
 5068     (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")
 5069     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
 5070     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
 5071     # var a: t
 5072     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/6")
 5073     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/7")
 5074     # foo a
 5075     (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")
 5076     #
 5077     (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")
 5078     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
 5079     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
 5080     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
 5081     (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")
 5082     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
 5083     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
 5084     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
 5085     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
 5086     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
 5087     (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")
 5088     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
 5089     (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")
 5090     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
 5091     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
 5092     # . epilogue
 5093     89/<- %esp 5/r32/ebp
 5094     5d/pop-to-ebp
 5095     c3/return
 5096 
 5097 test-convert-function-call-with-arg-of-user-defined-type-register-indirect:
 5098     # . prologue
 5099     55/push-ebp
 5100     89/<- %ebp 4/r32/esp
 5101     # setup
 5102     (clear-stream _test-input-stream)
 5103     (clear-stream $_test-input-buffered-file->buffer)
 5104     (clear-stream _test-output-stream)
 5105     (clear-stream $_test-output-buffered-file->buffer)
 5106     #
 5107     (write _test-input-stream "fn f {\n")
 5108     (write _test-input-stream "  var a/eax: (addr t) <- copy 0\n")
 5109     (write _test-input-stream "  foo *a\n")
 5110     (write _test-input-stream "}\n")
 5111     (write _test-input-stream "fn foo x: t {\n")
 5112     (write _test-input-stream "}\n")
 5113     (write _test-input-stream "type t {\n")
 5114     (write _test-input-stream "  x: int\n")
 5115     (write _test-input-stream "  y: int\n")
 5116     (write _test-input-stream "}\n")
 5117     # convert
 5118     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5119     (flush _test-output-buffered-file)
 5120 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5126     # check output
 5127     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
 5128     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
 5129     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
 5130     (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")
 5131     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
 5132     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
 5133     # var a
 5134     (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")
 5135     (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")
 5136     # foo a
 5137     (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")
 5138     #
 5139     (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")
 5140     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
 5141     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
 5142     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
 5143     (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")
 5144     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
 5145     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
 5146     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
 5147     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
 5148     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
 5149     (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")
 5150     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
 5151     (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")
 5152     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
 5153     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
 5154     # . epilogue
 5155     89/<- %esp 5/r32/ebp
 5156     5d/pop-to-ebp
 5157     c3/return
 5158 
 5159 # we don't have special support for call-by-reference; just explicitly create
 5160 # a new variable with the address of the arg
 5161 test-convert-function-call-with-arg-of-user-defined-type-by-reference:
 5162     # . prologue
 5163     55/push-ebp
 5164     89/<- %ebp 4/r32/esp
 5165     # setup
 5166     (clear-stream _test-input-stream)
 5167     (clear-stream $_test-input-buffered-file->buffer)
 5168     (clear-stream _test-output-stream)
 5169     (clear-stream $_test-output-buffered-file->buffer)
 5170     #
 5171     (write _test-input-stream "fn f {\n")
 5172     (write _test-input-stream "  var a: t\n")
 5173     (write _test-input-stream "  var b/eax: (addr t) <- address a\n")
 5174     (write _test-input-stream "  foo b\n")
 5175     (write _test-input-stream "}\n")
 5176     (write _test-input-stream "fn foo x: (addr t) {\n")
 5177     (write _test-input-stream "  var x/ecx: (addr int) <- copy x\n")
 5178     (write _test-input-stream "  increment *x\n")
 5179     (write _test-input-stream "}\n")
 5180     (write _test-input-stream "type t {\n")
 5181     (write _test-input-stream "  x: int\n")
 5182     (write _test-input-stream "  y: int\n")
 5183     (write _test-input-stream "}\n")
 5184     # convert
 5185     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5186     (flush _test-output-buffered-file)
 5187 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5193     # check output
 5194     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/0")
 5195     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/1")
 5196     (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")
 5197     (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")
 5198     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/4")
 5199     (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")
 5200     # var a: t
 5201     (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")
 5202     (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")
 5203     # var b/eax: (addr t)
 5204     (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")
 5205     (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")
 5206     # foo a
 5207     (check-next-stream-line-equal _test-output-stream "    (foo %eax)"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/10")
 5208     #
 5209     (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")
 5210     (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")
 5211     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/13")
 5212     (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")
 5213     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/15")
 5214     (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")
 5215     (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")
 5216     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/18")
 5217     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/19")
 5218     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/20")
 5219     (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")
 5220     (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")
 5221     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/23")
 5222     (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")
 5223     (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")
 5224     (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")
 5225     (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")
 5226     (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")
 5227     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/29")
 5228     (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")
 5229     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/31")
 5230     (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")
 5231     (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")
 5232     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/34")
 5233     # . epilogue
 5234     89/<- %esp 5/r32/ebp
 5235     5d/pop-to-ebp
 5236     c3/return
 5237 
 5238 test-convert-get-on-local-variable:
 5239     # . prologue
 5240     55/push-ebp
 5241     89/<- %ebp 4/r32/esp
 5242     # setup
 5243     (clear-stream _test-input-stream)
 5244     (clear-stream $_test-input-buffered-file->buffer)
 5245     (clear-stream _test-output-stream)
 5246     (clear-stream $_test-output-buffered-file->buffer)
 5247     #
 5248     (write _test-input-stream "fn foo {\n")
 5249     (write _test-input-stream "  var a: t\n")
 5250     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5251     (write _test-input-stream "}\n")
 5252     (write _test-input-stream "type t {\n")
 5253     (write _test-input-stream "  x: int\n")
 5254     (write _test-input-stream "  y: int\n")
 5255     (write _test-input-stream "}\n")
 5256     # convert
 5257     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5258     (flush _test-output-buffered-file)
 5259 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5265     # check output
 5266     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-local-variable/0")
 5267     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-local-variable/1")
 5268     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-local-variable/2")
 5269     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-local-variable/3")
 5270     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-local-variable/4")
 5271     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-local-variable/5")
 5272     # var a
 5273     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/6")
 5274     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/7")
 5275     # var c
 5276     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-local-variable/8")
 5277     # get
 5278     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000001/r32"  "F - test-convert-get-on-local-variable/9")
 5279     # reclaim c
 5280     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-local-variable/10")
 5281     # reclaim a
 5282     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000008/imm32"  "F - test-convert-get-on-local-variable/11")
 5283     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-local-variable/12")
 5284     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-local-variable/13")
 5285     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-local-variable/14")
 5286     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-local-variable/15")
 5287     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-local-variable/16")
 5288     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-local-variable/17")
 5289     # . epilogue
 5290     89/<- %esp 5/r32/ebp
 5291     5d/pop-to-ebp
 5292     c3/return
 5293 
 5294 test-convert-get-on-function-argument:
 5295     # . prologue
 5296     55/push-ebp
 5297     89/<- %ebp 4/r32/esp
 5298     # setup
 5299     (clear-stream _test-input-stream)
 5300     (clear-stream $_test-input-buffered-file->buffer)
 5301     (clear-stream _test-output-stream)
 5302     (clear-stream $_test-output-buffered-file->buffer)
 5303     #
 5304     (write _test-input-stream "fn foo a: t {\n")
 5305     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5306     (write _test-input-stream "}\n")
 5307     (write _test-input-stream "type t {\n")
 5308     (write _test-input-stream "  x: int\n")
 5309     (write _test-input-stream "  y: int\n")
 5310     (write _test-input-stream "}\n")
 5311     # convert
 5312     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5313     (flush _test-output-buffered-file)
 5314 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5320     # check output
 5321     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument/0")
 5322     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument/1")
 5323     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument/2")
 5324     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument/3")
 5325     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument/4")
 5326     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument/5")
 5327     # var c
 5328     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument/6")
 5329     # get
 5330     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0x0000000c) 0x00000001/r32"  "F - test-convert-get-on-function-argument/7")
 5331     # reclaim c
 5332     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument/8")
 5333     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument/9")
 5334     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument/10")
 5335     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument/11")
 5336     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument/12")
 5337     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument/13")
 5338     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument/14")
 5339     # . epilogue
 5340     89/<- %esp 5/r32/ebp
 5341     5d/pop-to-ebp
 5342     c3/return
 5343 
 5344 test-convert-get-on-function-argument-with-known-type:
 5345     # . prologue
 5346     55/push-ebp
 5347     89/<- %ebp 4/r32/esp
 5348     # setup
 5349     (clear-stream _test-input-stream)
 5350     (clear-stream $_test-input-buffered-file->buffer)
 5351     (clear-stream _test-output-stream)
 5352     (clear-stream $_test-output-buffered-file->buffer)
 5353     #
 5354     (write _test-input-stream "type t {\n")
 5355     (write _test-input-stream "  x: int\n")
 5356     (write _test-input-stream "  y: int\n")
 5357     (write _test-input-stream "}\n")
 5358     (write _test-input-stream "fn foo a: t {\n")
 5359     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5360     (write _test-input-stream "}\n")
 5361     # convert
 5362     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5363     (flush _test-output-buffered-file)
 5364 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5370     # check output
 5371     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument-with-known-type/0")
 5372     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument-with-known-type/1")
 5373     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument-with-known-type/2")
 5374     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument-with-known-type/3")
 5375     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument-with-known-type/4")
 5376     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument-with-known-type/5")
 5377     # var c
 5378     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument-with-known-type/6")
 5379     # get
 5380     (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")
 5381     # reclaim c
 5382     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument-with-known-type/8")
 5383     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument-with-known-type/9")
 5384     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument-with-known-type/10")
 5385     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument-with-known-type/11")
 5386     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument-with-known-type/12")
 5387     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument-with-known-type/13")
 5388     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument-with-known-type/14")
 5389     # . epilogue
 5390     89/<- %esp 5/r32/ebp
 5391     5d/pop-to-ebp
 5392     c3/return
 5393 
 5394 test-add-with-too-many-inouts:
 5395     # . prologue
 5396     55/push-ebp
 5397     89/<- %ebp 4/r32/esp
 5398     # setup
 5399     (clear-stream _test-input-stream)
 5400     (clear-stream $_test-input-buffered-file->buffer)
 5401     (clear-stream _test-output-stream)
 5402     (clear-stream $_test-output-buffered-file->buffer)
 5403     (clear-stream _test-error-stream)
 5404     (clear-stream $_test-error-buffered-file->buffer)
 5405     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5406     68/push 0/imm32
 5407     68/push 0/imm32
 5408     89/<- %edx 4/r32/esp
 5409     (tailor-exit-descriptor %edx 0x10)
 5410     #
 5411     (write _test-input-stream "fn foo {\n")
 5412     (write _test-input-stream "  var a: int\n")
 5413     (write _test-input-stream "  var b/ecx: int <- add a, 0\n")
 5414     (write _test-input-stream "}\n")
 5415     # convert
 5416     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5417     # registers except esp clobbered at this point
 5418     # restore ed
 5419     89/<- %edx 4/r32/esp
 5420     (flush _test-output-buffered-file)
 5421     (flush _test-error-buffered-file)
 5422 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5428     # check output
 5429     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-inouts: output should be empty")
 5430     (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")
 5431     # check that stop(1) was called
 5432     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-inouts: exit status")
 5433     # don't restore from ebp
 5434     81 0/subop/add %esp 8/imm32
 5435     # . epilogue
 5436     5d/pop-to-ebp
 5437     c3/return
 5438 
 5439 test-add-with-too-many-inouts-2:
 5440     # . prologue
 5441     55/push-ebp
 5442     89/<- %ebp 4/r32/esp
 5443     # setup
 5444     (clear-stream _test-input-stream)
 5445     (clear-stream $_test-input-buffered-file->buffer)
 5446     (clear-stream _test-output-stream)
 5447     (clear-stream $_test-output-buffered-file->buffer)
 5448     (clear-stream _test-error-stream)
 5449     (clear-stream $_test-error-buffered-file->buffer)
 5450     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5451     68/push 0/imm32
 5452     68/push 0/imm32
 5453     89/<- %edx 4/r32/esp
 5454     (tailor-exit-descriptor %edx 0x10)
 5455     #
 5456     (write _test-input-stream "fn foo {\n")
 5457     (write _test-input-stream "  var a: int\n")
 5458     (write _test-input-stream "  add-to a, 0, 1\n")
 5459     (write _test-input-stream "}\n")
 5460     # convert
 5461     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5462     # registers except esp clobbered at this point
 5463     # restore ed
 5464     89/<- %edx 4/r32/esp
 5465     (flush _test-output-buffered-file)
 5466     (flush _test-error-buffered-file)
 5467 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5473     # check output
 5474     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-inouts-2: output should be empty")
 5475     (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")
 5476     # check that stop(1) was called
 5477     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-inouts-2: exit status")
 5478     # don't restore from ebp
 5479     81 0/subop/add %esp 8/imm32
 5480     # . epilogue
 5481     5d/pop-to-ebp
 5482     c3/return
 5483 
 5484 test-add-with-too-many-outputs:
 5485     # . prologue
 5486     55/push-ebp
 5487     89/<- %ebp 4/r32/esp
 5488     # setup
 5489     (clear-stream _test-input-stream)
 5490     (clear-stream $_test-input-buffered-file->buffer)
 5491     (clear-stream _test-output-stream)
 5492     (clear-stream $_test-output-buffered-file->buffer)
 5493     (clear-stream _test-error-stream)
 5494     (clear-stream $_test-error-buffered-file->buffer)
 5495     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5496     68/push 0/imm32
 5497     68/push 0/imm32
 5498     89/<- %edx 4/r32/esp
 5499     (tailor-exit-descriptor %edx 0x10)
 5500     #
 5501     (write _test-input-stream "fn foo {\n")
 5502     (write _test-input-stream "  var a/eax: int <- copy 0\n")
 5503     (write _test-input-stream "  var b/ebx: int <- copy 0\n")
 5504     (write _test-input-stream "  var c/ecx: int <- copy 0\n")
 5505     (write _test-input-stream "  c, b <- add a\n")
 5506     (write _test-input-stream "}\n")
 5507     # convert
 5508     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5509     # registers except esp clobbered at this point
 5510     # restore ed
 5511     89/<- %edx 4/r32/esp
 5512     (flush _test-output-buffered-file)
 5513     (flush _test-error-buffered-file)
 5514 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5520     # check output
 5521     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-outputs: output should be empty")
 5522     (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")
 5523     # check that stop(1) was called
 5524     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-outputs: exit status")
 5525     # don't restore from ebp
 5526     81 0/subop/add %esp 8/imm32
 5527     # . epilogue
 5528     5d/pop-to-ebp
 5529     c3/return
 5530 
 5531 test-add-with-non-number:
 5532     # . prologue
 5533     55/push-ebp
 5534     89/<- %ebp 4/r32/esp
 5535     # setup
 5536     (clear-stream _test-input-stream)
 5537     (clear-stream $_test-input-buffered-file->buffer)
 5538     (clear-stream _test-output-stream)
 5539     (clear-stream $_test-output-buffered-file->buffer)
 5540     (clear-stream _test-error-stream)
 5541     (clear-stream $_test-error-buffered-file->buffer)
 5542     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5543     68/push 0/imm32
 5544     68/push 0/imm32
 5545     89/<- %edx 4/r32/esp
 5546     (tailor-exit-descriptor %edx 0x10)
 5547     #
 5548     (write _test-input-stream "fn foo {\n")
 5549     (write _test-input-stream "  var a: int\n")
 5550     (write _test-input-stream "  var b/ecx: (addr int) <- add a\n")
 5551     (write _test-input-stream "}\n")
 5552     # convert
 5553     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5554     # registers except esp clobbered at this point
 5555     # restore ed
 5556     89/<- %edx 4/r32/esp
 5557     (flush _test-output-buffered-file)
 5558     (flush _test-error-buffered-file)
 5559 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5565     # check output
 5566     (check-stream-equal _test-output-stream  ""  "F - test-add-with-non-number: output should be empty")
 5567     (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")
 5568     # check that stop(1) was called
 5569     (check-ints-equal *(edx+4) 2 "F - test-add-with-non-number: exit status")
 5570     # don't restore from ebp
 5571     81 0/subop/add %esp 8/imm32
 5572     # . epilogue
 5573     5d/pop-to-ebp
 5574     c3/return
 5575 
 5576 test-add-with-addr-dereferenced:
 5577     # . prologue
 5578     55/push-ebp
 5579     89/<- %ebp 4/r32/esp
 5580     # setup
 5581     (clear-stream _test-input-stream)
 5582     (clear-stream $_test-input-buffered-file->buffer)
 5583     (clear-stream _test-output-stream)
 5584     (clear-stream $_test-output-buffered-file->buffer)
 5585     #
 5586     (write _test-input-stream "fn foo {\n")
 5587     (write _test-input-stream "  var a/eax: (addr int) <- copy 0\n")
 5588     (write _test-input-stream "  add-to *a, 1\n")
 5589     (write _test-input-stream "}\n")
 5590     # convert
 5591     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5592     (flush _test-output-buffered-file)
 5593     # no error
 5594     # . epilogue
 5595     89/<- %esp 5/r32/ebp
 5596     5d/pop-to-ebp
 5597     c3/return
 5598 
 5599 test-get-with-wrong-field:
 5600     # . prologue
 5601     55/push-ebp
 5602     89/<- %ebp 4/r32/esp
 5603     # setup
 5604     (clear-stream _test-input-stream)
 5605     (clear-stream $_test-input-buffered-file->buffer)
 5606     (clear-stream _test-output-stream)
 5607     (clear-stream $_test-output-buffered-file->buffer)
 5608     (clear-stream _test-error-stream)
 5609     (clear-stream $_test-error-buffered-file->buffer)
 5610     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5611     68/push 0/imm32
 5612     68/push 0/imm32
 5613     89/<- %edx 4/r32/esp
 5614     (tailor-exit-descriptor %edx 0x10)
 5615     #
 5616     (write _test-input-stream "fn foo {\n")
 5617     (write _test-input-stream "  var a: t\n")
 5618     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5619     (write _test-input-stream "}\n")
 5620     (write _test-input-stream "type t {\n")
 5621     (write _test-input-stream "  x: int\n")
 5622     (write _test-input-stream "}\n")
 5623     # convert
 5624     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5625     # registers except esp clobbered at this point
 5626     # restore ed
 5627     89/<- %edx 4/r32/esp
 5628     (flush _test-output-buffered-file)
 5629     (flush _test-error-buffered-file)
 5630 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5636     # check output
 5637     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-field: output should be empty")
 5638     (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")
 5639     # check that stop(1) was called
 5640     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-field: exit status")
 5641     # don't restore from ebp
 5642     81 0/subop/add %esp 8/imm32
 5643     # . epilogue
 5644     5d/pop-to-ebp
 5645     c3/return
 5646 
 5647 test-get-with-wrong-base-type:
 5648     # . prologue
 5649     55/push-ebp
 5650     89/<- %ebp 4/r32/esp
 5651     # setup
 5652     (clear-stream _test-input-stream)
 5653     (clear-stream $_test-input-buffered-file->buffer)
 5654     (clear-stream _test-output-stream)
 5655     (clear-stream $_test-output-buffered-file->buffer)
 5656     (clear-stream _test-error-stream)
 5657     (clear-stream $_test-error-buffered-file->buffer)
 5658     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5659     68/push 0/imm32
 5660     68/push 0/imm32
 5661     89/<- %edx 4/r32/esp
 5662     (tailor-exit-descriptor %edx 0x10)
 5663     #
 5664     (write _test-input-stream "fn foo {\n")
 5665     (write _test-input-stream "  var a: int\n")
 5666     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5667     (write _test-input-stream "}\n")
 5668     # convert
 5669     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5670     # registers except esp clobbered at this point
 5671     # restore ed
 5672     89/<- %edx 4/r32/esp
 5673     (flush _test-output-buffered-file)
 5674     (flush _test-error-buffered-file)
 5675 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5681     # check output
 5682     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-base-type: output should be empty")
 5683     (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")
 5684     # check that stop(1) was called
 5685     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-base-type: exit status")
 5686     # don't restore from ebp
 5687     81 0/subop/add %esp 8/imm32
 5688     # . epilogue
 5689     5d/pop-to-ebp
 5690     c3/return
 5691 
 5692 test-get-with-wrong-base-type-2:
 5693     # . prologue
 5694     55/push-ebp
 5695     89/<- %ebp 4/r32/esp
 5696     # setup
 5697     (clear-stream _test-input-stream)
 5698     (clear-stream $_test-input-buffered-file->buffer)
 5699     (clear-stream _test-output-stream)
 5700     (clear-stream $_test-output-buffered-file->buffer)
 5701     (clear-stream _test-error-stream)
 5702     (clear-stream $_test-error-buffered-file->buffer)
 5703     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5704     68/push 0/imm32
 5705     68/push 0/imm32
 5706     89/<- %edx 4/r32/esp
 5707     (tailor-exit-descriptor %edx 0x10)
 5708     #
 5709     (write _test-input-stream "fn foo {\n")
 5710     (write _test-input-stream "  var a: (addr t)\n")
 5711     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5712     (write _test-input-stream "}\n")
 5713     (write _test-input-stream "type t {\n")
 5714     (write _test-input-stream "  x: int\n")
 5715     (write _test-input-stream "}\n")
 5716     # convert
 5717     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5718     # registers except esp clobbered at this point
 5719     # restore ed
 5720     89/<- %edx 4/r32/esp
 5721     (flush _test-output-buffered-file)
 5722     (flush _test-error-buffered-file)
 5723 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5729     # check output
 5730     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-base-type-2: output should be empty")
 5731     (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")
 5732     # check that stop(1) was called
 5733     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-base-type-2: exit status")
 5734     # don't restore from ebp
 5735     81 0/subop/add %esp 8/imm32
 5736     # . epilogue
 5737     5d/pop-to-ebp
 5738     c3/return
 5739 
 5740 test-get-with-wrong-offset-type:
 5741     # . prologue
 5742     55/push-ebp
 5743     89/<- %ebp 4/r32/esp
 5744     # setup
 5745     (clear-stream _test-input-stream)
 5746     (clear-stream $_test-input-buffered-file->buffer)
 5747     (clear-stream _test-output-stream)
 5748     (clear-stream $_test-output-buffered-file->buffer)
 5749     (clear-stream _test-error-stream)
 5750     (clear-stream $_test-error-buffered-file->buffer)
 5751     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5752     68/push 0/imm32
 5753     68/push 0/imm32
 5754     89/<- %edx 4/r32/esp
 5755     (tailor-exit-descriptor %edx 0x10)
 5756     #
 5757     (write _test-input-stream "fn foo {\n")
 5758     (write _test-input-stream "  var a: t\n")
 5759     (write _test-input-stream "  var b: int\n")
 5760     (write _test-input-stream "  var c/ecx: (addr int) <- get a, b\n")
 5761     (write _test-input-stream "}\n")
 5762     (write _test-input-stream "type t {\n")
 5763     (write _test-input-stream "  x: int\n")
 5764     (write _test-input-stream "}\n")
 5765     # convert
 5766     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5767     # registers except esp clobbered at this point
 5768     # restore ed
 5769     89/<- %edx 4/r32/esp
 5770     (flush _test-output-buffered-file)
 5771     (flush _test-error-buffered-file)
 5772 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5778     # check output
 5779     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-offset-type: output should be empty")
 5780     (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")
 5781     # check that stop(1) was called
 5782     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-offset-type: exit status")
 5783     # don't restore from ebp
 5784     81 0/subop/add %esp 8/imm32
 5785     # . epilogue
 5786     5d/pop-to-ebp
 5787     c3/return
 5788 
 5789 test-get-with-wrong-output-type:
 5790     # . prologue
 5791     55/push-ebp
 5792     89/<- %ebp 4/r32/esp
 5793     # setup
 5794     (clear-stream _test-input-stream)
 5795     (clear-stream $_test-input-buffered-file->buffer)
 5796     (clear-stream _test-output-stream)
 5797     (clear-stream $_test-output-buffered-file->buffer)
 5798     (clear-stream _test-error-stream)
 5799     (clear-stream $_test-error-buffered-file->buffer)
 5800     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5801     68/push 0/imm32
 5802     68/push 0/imm32
 5803     89/<- %edx 4/r32/esp
 5804     (tailor-exit-descriptor %edx 0x10)
 5805     #
 5806     (write _test-input-stream "fn foo {\n")
 5807     (write _test-input-stream "  var a: t\n")
 5808     (write _test-input-stream "  var c: (addr int)\n")
 5809     (write _test-input-stream "  c <- get a, x\n")
 5810     (write _test-input-stream "}\n")
 5811     (write _test-input-stream "type t {\n")
 5812     (write _test-input-stream "  x: int\n")
 5813     (write _test-input-stream "}\n")
 5814     # convert
 5815     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5816     # registers except esp clobbered at this point
 5817     # restore ed
 5818     89/<- %edx 4/r32/esp
 5819     (flush _test-output-buffered-file)
 5820     (flush _test-error-buffered-file)
 5821 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5827     # check output
 5828     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type: output should be empty")
 5829     (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")
 5830     # check that stop(1) was called
 5831     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type: exit status")
 5832     # don't restore from ebp
 5833     81 0/subop/add %esp 8/imm32
 5834     # . epilogue
 5835     5d/pop-to-ebp
 5836     c3/return
 5837 
 5838 test-get-with-wrong-output-type-2:
 5839     # . prologue
 5840     55/push-ebp
 5841     89/<- %ebp 4/r32/esp
 5842     # setup
 5843     (clear-stream _test-input-stream)
 5844     (clear-stream $_test-input-buffered-file->buffer)
 5845     (clear-stream _test-output-stream)
 5846     (clear-stream $_test-output-buffered-file->buffer)
 5847     (clear-stream _test-error-stream)
 5848     (clear-stream $_test-error-buffered-file->buffer)
 5849     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5850     68/push 0/imm32
 5851     68/push 0/imm32
 5852     89/<- %edx 4/r32/esp
 5853     (tailor-exit-descriptor %edx 0x10)
 5854     #
 5855     (write _test-input-stream "fn foo {\n")
 5856     (write _test-input-stream "  var a: t\n")
 5857     (write _test-input-stream "  var c/ecx: int <- get a, x\n")
 5858     (write _test-input-stream "}\n")
 5859     (write _test-input-stream "type t {\n")
 5860     (write _test-input-stream "  x: int\n")
 5861     (write _test-input-stream "}\n")
 5862     # convert
 5863     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5864     # registers except esp clobbered at this point
 5865     # restore ed
 5866     89/<- %edx 4/r32/esp
 5867     (flush _test-output-buffered-file)
 5868     (flush _test-error-buffered-file)
 5869 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5875     # check output
 5876     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-2: output should be empty")
 5877     (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")
 5878     # check that stop(1) was called
 5879     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-2: exit status")
 5880     # don't restore from ebp
 5881     81 0/subop/add %esp 8/imm32
 5882     # . epilogue
 5883     5d/pop-to-ebp
 5884     c3/return
 5885 
 5886 test-get-with-wrong-output-type-3:
 5887     # . prologue
 5888     55/push-ebp
 5889     89/<- %ebp 4/r32/esp
 5890     # setup
 5891     (clear-stream _test-input-stream)
 5892     (clear-stream $_test-input-buffered-file->buffer)
 5893     (clear-stream _test-output-stream)
 5894     (clear-stream $_test-output-buffered-file->buffer)
 5895     (clear-stream _test-error-stream)
 5896     (clear-stream $_test-error-buffered-file->buffer)
 5897     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5898     68/push 0/imm32
 5899     68/push 0/imm32
 5900     89/<- %edx 4/r32/esp
 5901     (tailor-exit-descriptor %edx 0x10)
 5902     #
 5903     (write _test-input-stream "fn foo {\n")
 5904     (write _test-input-stream "  var a: t\n")
 5905     (write _test-input-stream "  var c/ecx: (array int) <- get a, x\n")
 5906     (write _test-input-stream "}\n")
 5907     (write _test-input-stream "type t {\n")
 5908     (write _test-input-stream "  x: int\n")
 5909     (write _test-input-stream "}\n")
 5910     # convert
 5911     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5912     # registers except esp clobbered at this point
 5913     # restore ed
 5914     89/<- %edx 4/r32/esp
 5915     (flush _test-output-buffered-file)
 5916     (flush _test-error-buffered-file)
 5917 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5923     # check output
 5924     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-3: output should be empty")
 5925     (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")
 5926     # check that stop(1) was called
 5927     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-3: exit status")
 5928     # don't restore from ebp
 5929     81 0/subop/add %esp 8/imm32
 5930     # . epilogue
 5931     5d/pop-to-ebp
 5932     c3/return
 5933 
 5934 test-get-with-wrong-output-type-4:
 5935     # . prologue
 5936     55/push-ebp
 5937     89/<- %ebp 4/r32/esp
 5938     # setup
 5939     (clear-stream _test-input-stream)
 5940     (clear-stream $_test-input-buffered-file->buffer)
 5941     (clear-stream _test-output-stream)
 5942     (clear-stream $_test-output-buffered-file->buffer)
 5943     (clear-stream _test-error-stream)
 5944     (clear-stream $_test-error-buffered-file->buffer)
 5945     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5946     68/push 0/imm32
 5947     68/push 0/imm32
 5948     89/<- %edx 4/r32/esp
 5949     (tailor-exit-descriptor %edx 0x10)
 5950     #
 5951     (write _test-input-stream "fn foo {\n")
 5952     (write _test-input-stream "  var a: t\n")
 5953     (write _test-input-stream "  var c/ecx: (addr boolean) <- get a, x\n")
 5954     (write _test-input-stream "}\n")
 5955     (write _test-input-stream "type t {\n")
 5956     (write _test-input-stream "  x: int\n")
 5957     (write _test-input-stream "}\n")
 5958     # convert
 5959     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5960     # registers except esp clobbered at this point
 5961     # restore ed
 5962     89/<- %edx 4/r32/esp
 5963     (flush _test-output-buffered-file)
 5964     (flush _test-error-buffered-file)
 5965 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5971     # check output
 5972     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-4: output should be empty")
 5973     (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")
 5974     # check that stop(1) was called
 5975     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-4: exit status")
 5976     # don't restore from ebp
 5977     81 0/subop/add %esp 8/imm32
 5978     # . epilogue
 5979     5d/pop-to-ebp
 5980     c3/return
 5981 
 5982 test-get-with-wrong-output-type-5:
 5983     # . prologue
 5984     55/push-ebp
 5985     89/<- %ebp 4/r32/esp
 5986     # setup
 5987     (clear-stream _test-input-stream)
 5988     (clear-stream $_test-input-buffered-file->buffer)
 5989     (clear-stream _test-output-stream)
 5990     (clear-stream $_test-output-buffered-file->buffer)
 5991     #
 5992     (write _test-input-stream "fn foo {\n")
 5993     (write _test-input-stream "  var a: t\n")
 5994     (write _test-input-stream "  var c/ecx: (addr handle int) <- get a, x\n")
 5995     (write _test-input-stream "}\n")
 5996     (write _test-input-stream "type t {\n")
 5997     (write _test-input-stream "  x: (handle int)\n")
 5998     (write _test-input-stream "}\n")
 5999     # convert
 6000     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6001     (flush _test-output-buffered-file)
 6002     # no errors
 6003     # . epilogue
 6004     89/<- %esp 5/r32/ebp
 6005     5d/pop-to-ebp
 6006     c3/return
 6007 
 6008 test-get-with-too-few-inouts:
 6009     # . prologue
 6010     55/push-ebp
 6011     89/<- %ebp 4/r32/esp
 6012     # setup
 6013     (clear-stream _test-input-stream)
 6014     (clear-stream $_test-input-buffered-file->buffer)
 6015     (clear-stream _test-output-stream)
 6016     (clear-stream $_test-output-buffered-file->buffer)
 6017     (clear-stream _test-error-stream)
 6018     (clear-stream $_test-error-buffered-file->buffer)
 6019     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6020     68/push 0/imm32
 6021     68/push 0/imm32
 6022     89/<- %edx 4/r32/esp
 6023     (tailor-exit-descriptor %edx 0x10)
 6024     #
 6025     (write _test-input-stream "fn foo {\n")
 6026     (write _test-input-stream "  var a: t\n")
 6027     (write _test-input-stream "  var c/ecx: (addr int) <- get a\n")
 6028     (write _test-input-stream "}\n")
 6029     (write _test-input-stream "type t {\n")
 6030     (write _test-input-stream "  x: int\n")
 6031     (write _test-input-stream "}\n")
 6032     # convert
 6033     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6034     # registers except esp clobbered at this point
 6035     # restore ed
 6036     89/<- %edx 4/r32/esp
 6037     (flush _test-output-buffered-file)
 6038     (flush _test-error-buffered-file)
 6039 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6045     # check output
 6046     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-few-inouts: output should be empty")
 6047     (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")
 6048     # check that stop(1) was called
 6049     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-few-inouts: exit status")
 6050     # don't restore from ebp
 6051     81 0/subop/add %esp 8/imm32
 6052     # . epilogue
 6053     5d/pop-to-ebp
 6054     c3/return
 6055 
 6056 test-get-with-too-many-inouts:
 6057     # . prologue
 6058     55/push-ebp
 6059     89/<- %ebp 4/r32/esp
 6060     # setup
 6061     (clear-stream _test-input-stream)
 6062     (clear-stream $_test-input-buffered-file->buffer)
 6063     (clear-stream _test-output-stream)
 6064     (clear-stream $_test-output-buffered-file->buffer)
 6065     (clear-stream _test-error-stream)
 6066     (clear-stream $_test-error-buffered-file->buffer)
 6067     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6068     68/push 0/imm32
 6069     68/push 0/imm32
 6070     89/<- %edx 4/r32/esp
 6071     (tailor-exit-descriptor %edx 0x10)
 6072     #
 6073     (write _test-input-stream "fn foo {\n")
 6074     (write _test-input-stream "  var a: t\n")
 6075     (write _test-input-stream "  var c/ecx: (addr int) <- get a, x, 0\n")
 6076     (write _test-input-stream "}\n")
 6077     (write _test-input-stream "type t {\n")
 6078     (write _test-input-stream "  x: int\n")
 6079     (write _test-input-stream "}\n")
 6080     # convert
 6081     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6082     # registers except esp clobbered at this point
 6083     # restore ed
 6084     89/<- %edx 4/r32/esp
 6085     (flush _test-output-buffered-file)
 6086     (flush _test-error-buffered-file)
 6087 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6093     # check output
 6094     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-many-inouts: output should be empty")
 6095     (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")
 6096     # check that stop(1) was called
 6097     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-many-inouts: exit status")
 6098     # don't restore from ebp
 6099     81 0/subop/add %esp 8/imm32
 6100     # . epilogue
 6101     5d/pop-to-ebp
 6102     c3/return
 6103 
 6104 test-get-with-no-output:
 6105     # . prologue
 6106     55/push-ebp
 6107     89/<- %ebp 4/r32/esp
 6108     # setup
 6109     (clear-stream _test-input-stream)
 6110     (clear-stream $_test-input-buffered-file->buffer)
 6111     (clear-stream _test-output-stream)
 6112     (clear-stream $_test-output-buffered-file->buffer)
 6113     (clear-stream _test-error-stream)
 6114     (clear-stream $_test-error-buffered-file->buffer)
 6115     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6116     68/push 0/imm32
 6117     68/push 0/imm32
 6118     89/<- %edx 4/r32/esp
 6119     (tailor-exit-descriptor %edx 0x10)
 6120     #
 6121     (write _test-input-stream "fn foo {\n")
 6122     (write _test-input-stream "  var a: t\n")
 6123     (write _test-input-stream "  get a, x\n")
 6124     (write _test-input-stream "}\n")
 6125     (write _test-input-stream "type t {\n")
 6126     (write _test-input-stream "  x: int\n")
 6127     (write _test-input-stream "}\n")
 6128     # convert
 6129     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6130     # registers except esp clobbered at this point
 6131     # restore ed
 6132     89/<- %edx 4/r32/esp
 6133     (flush _test-output-buffered-file)
 6134     (flush _test-error-buffered-file)
 6135 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6141     # check output
 6142     (check-stream-equal _test-output-stream  ""  "F - test-get-with-no-output: output should be empty")
 6143     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: must have an output"  "F - test-get-with-no-output: error message")
 6144     # check that stop(1) was called
 6145     (check-ints-equal *(edx+4) 2 "F - test-get-with-no-output: exit status")
 6146     # don't restore from ebp
 6147     81 0/subop/add %esp 8/imm32
 6148     # . epilogue
 6149     5d/pop-to-ebp
 6150     c3/return
 6151 
 6152 test-get-with-too-many-outputs:
 6153     # . prologue
 6154     55/push-ebp
 6155     89/<- %ebp 4/r32/esp
 6156     # setup
 6157     (clear-stream _test-input-stream)
 6158     (clear-stream $_test-input-buffered-file->buffer)
 6159     (clear-stream _test-output-stream)
 6160     (clear-stream $_test-output-buffered-file->buffer)
 6161     (clear-stream _test-error-stream)
 6162     (clear-stream $_test-error-buffered-file->buffer)
 6163     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6164     68/push 0/imm32
 6165     68/push 0/imm32
 6166     89/<- %edx 4/r32/esp
 6167     (tailor-exit-descriptor %edx 0x10)
 6168     #
 6169     (write _test-input-stream "fn foo {\n")
 6170     (write _test-input-stream "  var a: t\n")
 6171     (write _test-input-stream "  var b: int\n")
 6172     (write _test-input-stream "  var c/eax: (addr int) <- copy 0\n")
 6173     (write _test-input-stream "  c, b <- get a, x\n")
 6174     (write _test-input-stream "}\n")
 6175     (write _test-input-stream "type t {\n")
 6176     (write _test-input-stream "  x: int\n")
 6177     (write _test-input-stream "}\n")
 6178     # convert
 6179     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6180     # registers except esp clobbered at this point
 6181     # restore ed
 6182     89/<- %edx 4/r32/esp
 6183     (flush _test-output-buffered-file)
 6184     (flush _test-error-buffered-file)
 6185 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6191     # check output
 6192     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-many-outputs: output should be empty")
 6193     (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")
 6194     # check that stop(1) was called
 6195     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-many-outputs: exit status")
 6196     # don't restore from ebp
 6197     81 0/subop/add %esp 8/imm32
 6198     # . epilogue
 6199     5d/pop-to-ebp
 6200     c3/return
 6201 
 6202 test-convert-array-of-user-defined-types:
 6203     # . prologue
 6204     55/push-ebp
 6205     89/<- %ebp 4/r32/esp
 6206     # setup
 6207     (clear-stream _test-input-stream)
 6208     (clear-stream $_test-input-buffered-file->buffer)
 6209     (clear-stream _test-output-stream)
 6210     (clear-stream $_test-output-buffered-file->buffer)
 6211     #
 6212     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
 6213     (write _test-input-stream "  x: int\n")
 6214     (write _test-input-stream "  y: int\n")
 6215     (write _test-input-stream "}\n")
 6216     (write _test-input-stream "fn foo {\n")
 6217     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6218     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 6219     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 6220     (write _test-input-stream "}\n")
 6221     # convert
 6222     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6223     (flush _test-output-buffered-file)
 6224 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 6230     # check output
 6231     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-array-of-user-defined-types/0")
 6232     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-array-of-user-defined-types/1")
 6233     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-array-of-user-defined-types/2")
 6234     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-array-of-user-defined-types/3")
 6235     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-array-of-user-defined-types/4")
 6236     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-array-of-user-defined-types/5")
 6237     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-array-of-user-defined-types/6")
 6238     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-array-of-user-defined-types/7")
 6239     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-array-of-user-defined-types/8")
 6240     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-array-of-user-defined-types/9")
 6241     (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")
 6242     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-array-of-user-defined-types/13")
 6243     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-array-of-user-defined-types/14")
 6244     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-array-of-user-defined-types/15")
 6245     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-array-of-user-defined-types/16")
 6246     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-array-of-user-defined-types/17")
 6247     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-array-of-user-defined-types/18")
 6248     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-array-of-user-defined-types/19")
 6249     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-array-of-user-defined-types/20")
 6250     # . epilogue
 6251     89/<- %esp 5/r32/ebp
 6252     5d/pop-to-ebp
 6253     c3/return
 6254 
 6255 test-convert-length-of-array-of-user-defined-types-to-eax:
 6256     # . prologue
 6257     55/push-ebp
 6258     89/<- %ebp 4/r32/esp
 6259     # setup
 6260     (clear-stream _test-input-stream)
 6261     (clear-stream $_test-input-buffered-file->buffer)
 6262     (clear-stream _test-output-stream)
 6263     (clear-stream $_test-output-buffered-file->buffer)
 6264     #
 6265     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 6266     (write _test-input-stream "  x: int\n")
 6267     (write _test-input-stream "  y: int\n")
 6268     (write _test-input-stream "  z: int\n")
 6269     (write _test-input-stream "}\n")
 6270     (write _test-input-stream "fn foo {\n")
 6271     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6272     (write _test-input-stream "  var x/eax: (addr t) <- length arr\n")
 6273     (write _test-input-stream "}\n")
 6274     # convert
 6275     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6276     (flush _test-output-buffered-file)
 6277 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 6283     # check output
 6284     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-eax/0")
 6285     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/1")
 6286     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-eax/2")
 6287     (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")
 6288     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/4")
 6289     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-eax/5")
 6290     # var arr
 6291     (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")
 6292     (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")
 6293     # length instruction
 6294     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/8")
 6295     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/9")
 6296     (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")
 6297     (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")
 6298     (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")
 6299     (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")
 6300     (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")
 6301     (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")
 6302     # reclaim arr
 6303     (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")
 6304     #
 6305     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/17")
 6306     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/18")
 6307     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/19")
 6308     (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")
 6309     (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")
 6310     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-eax/22")
 6311     # . epilogue
 6312     89/<- %esp 5/r32/ebp
 6313     5d/pop-to-ebp
 6314     c3/return
 6315 
 6316 test-convert-length-of-array-of-user-defined-types-to-ecx:
 6317     # . prologue
 6318     55/push-ebp
 6319     89/<- %ebp 4/r32/esp
 6320     # setup
 6321     (clear-stream _test-input-stream)
 6322     (clear-stream $_test-input-buffered-file->buffer)
 6323     (clear-stream _test-output-stream)
 6324     (clear-stream $_test-output-buffered-file->buffer)
 6325     #
 6326     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 6327     (write _test-input-stream "  x: int\n")
 6328     (write _test-input-stream "  y: int\n")
 6329     (write _test-input-stream "  z: int\n")
 6330     (write _test-input-stream "}\n")
 6331     (write _test-input-stream "fn foo {\n")
 6332     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6333     (write _test-input-stream "  var x/ecx: (addr t) <- length arr\n")
 6334     (write _test-input-stream "}\n")
 6335     # convert
 6336     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6337     (flush _test-output-buffered-file)
 6338 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 6344     # check output
 6345     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-ecx/0")
 6346     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/1")
 6347     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-ecx/2")
 6348     (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")
 6349     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/4")
 6350     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-ecx/5")
 6351     # var a
 6352     (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")
 6353     (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")
 6354     # var x
 6355     (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")
 6356     # length instruction
 6357     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/9")
 6358     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/10")
 6359     (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")
 6360     (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")
 6361     (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")
 6362     (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")
 6363     (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")
 6364     (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")
 6365     (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")
 6366     # reclaim x
 6367     (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")
 6368     # reclaim a
 6369     (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")
 6370     #
 6371     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/20")
 6372     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/21")
 6373     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/22")
 6374     (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")
 6375     (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")
 6376     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-ecx/25")
 6377     # . epilogue
 6378     89/<- %esp 5/r32/ebp
 6379     5d/pop-to-ebp
 6380     c3/return
 6381 
 6382 test-convert-length-of-array-of-user-defined-types-to-edx:
 6383     # . prologue
 6384     55/push-ebp
 6385     89/<- %ebp 4/r32/esp
 6386     # setup
 6387     (clear-stream _test-input-stream)
 6388     (clear-stream $_test-input-buffered-file->buffer)
 6389     (clear-stream _test-output-stream)
 6390     (clear-stream $_test-output-buffered-file->buffer)
 6391     #
 6392     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 6393     (write _test-input-stream "  x: int\n")
 6394     (write _test-input-stream "  y: int\n")
 6395     (write _test-input-stream "  z: int\n")
 6396     (write _test-input-stream "}\n")
 6397     (write _test-input-stream "fn foo {\n")
 6398     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6399     (write _test-input-stream "  var x/edx: (addr t) <- length arr\n")
 6400     (write _test-input-stream "}\n")
 6401     # convert
 6402     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6403     (flush _test-output-buffered-file)
 6404 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 6410     # check output
 6411     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-edx/0")
 6412     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/1")
 6413     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-edx/2")
 6414     (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")
 6415     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/4")
 6416     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-edx/5")
 6417     # var a
 6418     (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")
 6419     (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")
 6420     # var x
 6421     (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")
 6422     # length instruction
 6423     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/9")
 6424     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/10")
 6425     (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")
 6426     (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")
 6427     (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")
 6428     (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")
 6429     (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")
 6430     (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")
 6431     (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")
 6432     # reclaim x
 6433     (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")
 6434     # reclaim a
 6435     (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")
 6436     #
 6437     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/20")
 6438     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/21")
 6439     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/22")
 6440     (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")
 6441     (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")
 6442     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-edx/25")
 6443     # . epilogue
 6444     89/<- %esp 5/r32/ebp
 6445     5d/pop-to-ebp
 6446     c3/return
 6447 
 6448 test-convert-length-of-array-of-user-defined-types:
 6449     # . prologue
 6450     55/push-ebp
 6451     89/<- %ebp 4/r32/esp
 6452     # setup
 6453     (clear-stream _test-input-stream)
 6454     (clear-stream $_test-input-buffered-file->buffer)
 6455     (clear-stream _test-output-stream)
 6456     (clear-stream $_test-output-buffered-file->buffer)
 6457     #
 6458     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
 6459     (write _test-input-stream "  x: int\n")
 6460     (write _test-input-stream "  y: int\n")
 6461     (write _test-input-stream "  z: int\n")
 6462     (write _test-input-stream "}\n")
 6463     (write _test-input-stream "fn foo {\n")
 6464     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6465     (write _test-input-stream "  var x/ebx: (addr t) <- length arr\n")
 6466     (write _test-input-stream "}\n")
 6467     # convert
 6468     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6469     (flush _test-output-buffered-file)
 6470 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 6476     # check output
 6477     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types/0")
 6478     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types/1")
 6479     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types/2")
 6480     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-user-defined-types/3")
 6481     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types/4")
 6482     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types/5")
 6483     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-user-defined-types/6")
 6484     (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")
 6485     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ebx"  "F - test-convert-length-of-array-of-user-defined-types/8")
 6486     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types/9")
 6487     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types/10")
 6488     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types/11")
 6489     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-user-defined-types/12")
 6490     (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")
 6491     (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")
 6492     (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")
 6493     (check-next-stream-line-equal _test-output-stream "    89/<- %ebx 0/r32/eax"  "F - test-convert-length-of-array-of-user-defined-types/16")
 6494     (check-next-stream-line-equal _test-output-stream "    5a/pop-to-edx"       "F - test-convert-length-of-array-of-user-defined-types/17")
 6495     (check-next-stream-line-equal _test-output-stream "    59/pop-to-ecx"       "F - test-convert-length-of-array-of-user-defined-types/18")
 6496     (check-next-stream-line-equal _test-output-stream "    58/pop-to-eax"       "F - test-convert-length-of-array-of-user-defined-types/19")
 6497     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ebx"  "F - test-convert-length-of-array-of-user-defined-types/20")
 6498     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-user-defined-types/21")
 6499     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types/22")
 6500     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types/23")
 6501     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types/24")
 6502     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-user-defined-types/25")
 6503     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-user-defined-types/26")
 6504     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types/27")
 6505     # . epilogue
 6506     89/<- %esp 5/r32/ebp
 6507     5d/pop-to-ebp
 6508     c3/return
 6509 
 6510 #######################################################
 6511 # Parsing
 6512 #######################################################
 6513 
 6514 == data
 6515 
 6516 # Global state added to each var record when parsing a function
 6517 Next-block-index:  # (addr int)
 6518     1/imm32
 6519 
 6520 Curr-block-depth:  # (addr int)
 6521     1/imm32
 6522 
 6523 == code
 6524 
 6525 parse-mu:  # in: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
 6526     # pseudocode
 6527     #   var curr-function: (addr handle function) = Program->functions
 6528     #   var curr-signature: (addr handle function) = Program->signatures
 6529     #   var curr-type: (addr handle typeinfo) = Program->types
 6530     #   var line: (stream byte 512)
 6531     #   var word-slice: slice
 6532     #   while true                                  # line loop
 6533     #     clear-stream(line)
 6534     #     read-line-buffered(in, line)
 6535     #     if (line->write == 0) break               # end of file
 6536     #     word-slice = next-mu-token(line)
 6537     #     if slice-empty?(word-slice)               # end of line
 6538     #       continue
 6539     #     else if slice-starts-with?(word-slice, "#")  # comment
 6540     #       continue                                # end of line
 6541     #     else if slice-equal?(word-slice, "fn")
 6542     #       var new-function: (handle function) = allocate(function)
 6543     #       var vars: (stack live-var 256)
 6544     #       populate-mu-function-header(line, new-function, vars)
 6545     #       populate-mu-function-body(in, new-function, vars)
 6546     #       assert(vars->top == 0)
 6547     #       *curr-function = new-function
 6548     #       curr-function = &new-function->next
 6549     #     else if slice-equal?(word-slice, "sig")
 6550     #       var new-function: (handle function) = allocate(function)
 6551     #       populate-mu-function-signature(line, new-function)
 6552     #       *curr-signature = new-function
 6553     #       curr-signature = &new-function->next
 6554     #     else if slice-equal?(word-slice, "type")
 6555     #       word-slice = next-mu-token(line)
 6556     #       type-id = pos-or-insert-slice(Type-id, word-slice)
 6557     #       var new-type: (handle typeinfo) = find-or-create-typeinfo(type-id)
 6558     #       assert(next-word(line) == "{")
 6559     #       populate-mu-type(in, new-type)
 6560     #     else
 6561     #       abort()
 6562     #
 6563     # . prologue
 6564     55/push-ebp
 6565     89/<- %ebp 4/r32/esp
 6566     # var curr-signature: (addr handle function) at *(ebp-4)
 6567     68/push _Program-signatures/imm32
 6568     # . save registers
 6569     50/push-eax
 6570     51/push-ecx
 6571     52/push-edx
 6572     53/push-ebx
 6573     56/push-esi
 6574     57/push-edi
 6575     # var line/ecx: (stream byte 512)
 6576     81 5/subop/subtract %esp 0x200/imm32
 6577     68/push 0x200/imm32/size
 6578     68/push 0/imm32/read
 6579     68/push 0/imm32/write
 6580     89/<- %ecx 4/r32/esp
 6581     # var word-slice/edx: slice
 6582     68/push 0/imm32/end
 6583     68/push 0/imm32/start
 6584     89/<- %edx 4/r32/esp
 6585     # var curr-function/edi: (addr handle function)
 6586     bf/copy-to-edi _Program-functions/imm32
 6587     # var vars/ebx: (stack live-var 256)
 6588     81 5/subop/subtract %esp 0xc00/imm32
 6589     68/push 0xc00/imm32/size
 6590     68/push 0/imm32/top
 6591     89/<- %ebx 4/r32/esp
 6592     {
 6593 $parse-mu:line-loop:
 6594       (clear-stream %ecx)
 6595       (read-line-buffered *(ebp+8) %ecx)
 6596       # if (line->write == 0) break
 6597       81 7/subop/compare *ecx 0/imm32
 6598       0f 84/jump-if-= break/disp32
 6599 +--  6 lines: #?       # dump line ------------------------------------------------------------------------------------------------------------------------------------------------------
 6605       (next-mu-token %ecx %edx)
 6606       # if slice-empty?(word-slice) continue
 6607       (slice-empty? %edx)  # => eax
 6608       3d/compare-eax-and 0/imm32/false
 6609       0f 85/jump-if-!= loop/disp32
 6610       # if (*word-slice->start == "#") continue
 6611       # . eax = *word-slice->start
 6612       8b/-> *edx 0/r32/eax
 6613       8a/copy-byte *eax 0/r32/AL
 6614       81 4/subop/and %eax 0xff/imm32
 6615       # . if (eax == '#') continue
 6616       3d/compare-eax-and 0x23/imm32/hash
 6617       0f 84/jump-if-= loop/disp32
 6618       # if (slice-equal?(word-slice, "fn")) parse a function
 6619       {
 6620 $parse-mu:fn:
 6621         (slice-equal? %edx "fn")  # => eax
 6622         3d/compare-eax-and 0/imm32/false
 6623         0f 84/jump-if-= break/disp32
 6624         # var new-function/esi: (handle function)
 6625         68/push 0/imm32
 6626         68/push 0/imm32
 6627         89/<- %esi 4/r32/esp
 6628         # populate-mu-function(line, in, vars, new-function)
 6629         (allocate Heap *Function-size %esi)
 6630         # var new-function-addr/eax: (addr function)
 6631         (lookup *esi *(esi+4))  # => eax
 6632         # initialize vars
 6633         (clear-stack %ebx)
 6634         #
 6635         (populate-mu-function-header %ecx %eax %ebx *(ebp+0xc) *(ebp+0x10))
 6636         (populate-mu-function-body *(ebp+8) %eax %ebx *(ebp+0xc) *(ebp+0x10))
 6637         # *curr-function = new-function
 6638         8b/-> *esi 0/r32/eax
 6639         89/<- *edi 0/r32/eax
 6640         8b/-> *(esi+4) 0/r32/eax
 6641         89/<- *(edi+4) 0/r32/eax
 6642         # curr-function = &new-function->next
 6643         # . var tmp/eax: (addr function) = lookup(new-function)
 6644         (lookup *esi *(esi+4))  # => eax
 6645         # . curr-function = &tmp->next
 6646         8d/copy-address *(eax+0x20) 7/r32/edi  # Function-next
 6647         # reclaim new-function
 6648         81 0/subop/add %esp 8/imm32
 6649         #
 6650         e9/jump $parse-mu:line-loop/disp32
 6651       }
 6652       # if (slice-equal?(word-slice, "sig")) parse a function signature
 6653       # Function signatures are for providing types to SubX functions.
 6654       {
 6655 $parse-mu:sig:
 6656         (slice-equal? %edx "sig")  # => eax
 6657         3d/compare-eax-and 0/imm32/false
 6658         0f 84/jump-if-= break/disp32
 6659         # edi = curr-function
 6660         57/push-edi
 6661         8b/-> *(ebp-4) 7/r32/edi
 6662         # var new-function/esi: (handle function)
 6663         68/push 0/imm32
 6664         68/push 0/imm32
 6665         89/<- %esi 4/r32/esp
 6666         # populate-mu-function(line, in, vars, new-function)
 6667         (allocate Heap *Function-size %esi)
 6668         # var new-function-addr/eax: (addr function)
 6669         (lookup *esi *(esi+4))  # => eax
 6670         #
 6671         (populate-mu-function-signature %ecx %eax *(ebp+0xc) *(ebp+0x10))
 6672         # *curr-signature = new-function
 6673         8b/-> *esi 0/r32/eax
 6674         89/<- *edi 0/r32/eax
 6675         8b/-> *(esi+4) 0/r32/eax
 6676         89/<- *(edi+4) 0/r32/eax
 6677         # curr-signature = &new-function->next
 6678         # . var tmp/eax: (addr function) = lookup(new-function)
 6679         (lookup *esi *(esi+4))  # => eax
 6680         # . curr-function = &tmp->next
 6681         8d/copy-address *(eax+0x20) 7/r32/edi  # Function-next
 6682         # reclaim new-function
 6683         81 0/subop/add %esp 8/imm32
 6684         # save curr-function
 6685         89/<- *(ebp-4) 7/r32/edi
 6686         # restore edi
 6687         5f/pop-to-edi
 6688         #
 6689         e9/jump $parse-mu:line-loop/disp32
 6690       }
 6691       # if (slice-equal?(word-slice, "type")) parse a type (struct/record) definition
 6692       {
 6693 $parse-mu:type:
 6694         (slice-equal? %edx "type")  # => eax
 6695         3d/compare-eax-and 0/imm32
 6696         0f 84/jump-if-= break/disp32
 6697         (next-mu-token %ecx %edx)
 6698         # var type-id/eax: int
 6699         (pos-or-insert-slice Type-id %edx)  # => eax
 6700         # spill
 6701         51/push-ecx
 6702         # var new-type/ecx: (handle typeinfo)
 6703         68/push 0/imm32
 6704         68/push 0/imm32
 6705         89/<- %ecx 4/r32/esp
 6706         (find-or-create-typeinfo %eax %ecx)
 6707         #
 6708         (lookup *ecx *(ecx+4))  # => eax
 6709         # TODO: ensure that 'line' has nothing else but '{'
 6710 #? (dump-typeinfos "=== aaa\n")
 6711         (populate-mu-type *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))  # => eax
 6712 #? (dump-typeinfos "=== zzz\n")
 6713         # reclaim new-type
 6714         81 0/subop/add %esp 8/imm32
 6715         # restore
 6716         59/pop-to-ecx
 6717         e9/jump $parse-mu:line-loop/disp32
 6718       }
 6719       # otherwise abort
 6720       e9/jump $parse-mu:error1/disp32
 6721     } # end line loop
 6722 $parse-mu:end:
 6723     # . reclaim locals
 6724     81 0/subop/add %esp 0x20c/imm32  # line
 6725     81 0/subop/add %esp 0xc08/imm32  # vars
 6726     81 0/subop/add %esp 8/imm32
 6727     # . restore registers
 6728     5f/pop-to-edi
 6729     5e/pop-to-esi
 6730     5b/pop-to-ebx
 6731     5a/pop-to-edx
 6732     59/pop-to-ecx
 6733     58/pop-to-eax
 6734     # . reclaim local
 6735     81 0/subop/add %esp 4/imm32
 6736     # . epilogue
 6737     89/<- %esp 5/r32/ebp
 6738     5d/pop-to-ebp
 6739     c3/return
 6740 
 6741 $parse-mu:error1:
 6742     # error("unexpected top-level command: " word-slice "\n")
 6743     (write-buffered *(ebp+0xc) "unexpected top-level command: ")
 6744     (write-slice-buffered *(ebp+0xc) %edx)
 6745     (write-buffered *(ebp+0xc) "\n")
 6746     (flush *(ebp+0xc))
 6747     (stop *(ebp+0x10) 1)
 6748     # never gets here
 6749 
 6750 $parse-mu:error2:
 6751     # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n")
 6752     (write-int32-hex-buffered *(ebp+0xc) *ebx)
 6753     (write-buffered *(ebp+0xc) " vars not reclaimed after fn '")
 6754     (write-slice-buffered *(ebp+0xc) *eax)  # Function-name
 6755     (write-buffered *(ebp+0xc) "'\n")
 6756     (flush *(ebp+0xc))
 6757     (stop *(ebp+0x10) 1)
 6758     # never gets here
 6759 
 6760 # scenarios considered:
 6761 # ✗ fn foo  # no block
 6762 # ✓ fn foo {
 6763 # ✗ fn foo { {
 6764 # ✗ fn foo { }
 6765 # ✗ fn foo { } {
 6766 # ✗ fn foo x {
 6767 # ✗ fn foo x: {
 6768 # ✓ fn foo x: int {
 6769 # ✓ fn foo x: int {
 6770 # ✓ fn foo x: int -> y/eax: int {
 6771 # TODO:
 6772 #   disallow outputs of type `(... addr ...)`
 6773 #   disallow inputs of type `(... addr ... addr ...)`
 6774 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)
 6775     # pseudocode:
 6776     #   var word-slice: slice
 6777     #   next-mu-token(first-line, word-slice)
 6778     #   assert(word-slice not in '{' '}' '->')
 6779     #   out->name = slice-to-string(word-slice)
 6780     #   ## inouts
 6781     #   while true
 6782     #     word-slice = next-mu-token(first-line)
 6783     #     if (word-slice == '{') goto done
 6784     #     if (word-slice == '->') break
 6785     #     assert(word-slice != '}')
 6786     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 6787     #     assert(v->register == null)
 6788     #     # v->block-depth is implicitly 0
 6789     #     out->inouts = append(v, out->inouts)
 6790     #     push(vars, {v, false})
 6791     #   ## outputs
 6792     #   while true
 6793     #     word-slice = next-mu-token(first-line)
 6794     #     if (word-slice == '{') break
 6795     #     assert(word-slice not in '}' '->')
 6796     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 6797     #     assert(v->register != null)
 6798     #     out->outputs = append(v, out->outputs)
 6799     #   done:
 6800     #
 6801     # . prologue
 6802     55/push-ebp
 6803     89/<- %ebp 4/r32/esp
 6804     # . save registers
 6805     50/push-eax
 6806     51/push-ecx
 6807     52/push-edx
 6808     53/push-ebx
 6809     57/push-edi
 6810     # edi = out
 6811     8b/-> *(ebp+0xc) 7/r32/edi
 6812     # var word-slice/ecx: slice
 6813     68/push 0/imm32/end
 6814     68/push 0/imm32/start
 6815     89/<- %ecx 4/r32/esp
 6816     # var v/ebx: (handle var)
 6817     68/push 0/imm32
 6818     68/push 0/imm32
 6819     89/<- %ebx 4/r32/esp
 6820     # read function name
 6821     (next-mu-token *(ebp+8) %ecx)
 6822     # error checking
 6823     # if (word-slice == '{') abort
 6824     (slice-equal? %ecx "{")   # => eax
 6825     3d/compare-eax-and 0/imm32/false
 6826     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6827     # if (word-slice == '->') abort
 6828     (slice-equal? %ecx "->")   # => eax
 6829     3d/compare-eax-and 0/imm32/false
 6830     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6831     # if (word-slice == '}') abort
 6832     (slice-equal? %ecx "}")   # => eax
 6833     3d/compare-eax-and 0/imm32/false
 6834     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6835     # save function name
 6836     (slice-to-string Heap %ecx %edi)  # Function-name
 6837     # save function inouts
 6838     {
 6839 $populate-mu-function-header:check-for-inout:
 6840       (next-mu-token *(ebp+8) %ecx)
 6841       # if (word-slice == '{') goto done
 6842       (slice-equal? %ecx "{")   # => eax
 6843       3d/compare-eax-and 0/imm32/false
 6844       0f 85/jump-if-!= $populate-mu-function-header:done/disp32
 6845       # if (word-slice == '->') break
 6846       (slice-equal? %ecx "->")   # => eax
 6847       3d/compare-eax-and 0/imm32/false
 6848       0f 85/jump-if-!= break/disp32
 6849       # if (word-slice == '}') abort
 6850       (slice-equal? %ecx "}")   # => eax
 6851       3d/compare-eax-and 0/imm32/false
 6852       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6853       # v = parse-var-with-type(word-slice, first-line)
 6854       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x14) *(ebp+0x18))
 6855       # assert(v->register == null)
 6856       # . eax: (addr var) = lookup(v)
 6857       (lookup *ebx *(ebx+4))  # => eax
 6858       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 6859       0f 85/jump-if-!= $populate-mu-function-header:error2/disp32
 6860       # v->block-depth is implicitly 0
 6861       #
 6862       # out->inouts = append(v, out->inouts)
 6863       8d/copy-address *(edi+8) 0/r32/eax  # Function-inouts
 6864       (append-list Heap  *ebx *(ebx+4)  *(edi+8) *(edi+0xc)  %eax)  # Function-inouts, Function-inouts
 6865       # push(vars, {v, false})
 6866       (push *(ebp+0x10) *ebx)
 6867       (push *(ebp+0x10) *(ebx+4))
 6868       (push *(ebp+0x10) 0)  # false
 6869       #
 6870       e9/jump loop/disp32
 6871     }
 6872     # save function outputs
 6873     {
 6874 $populate-mu-function-header:check-for-out:
 6875       (next-mu-token *(ebp+8) %ecx)
 6876       # if (word-slice == '{') break
 6877       (slice-equal? %ecx "{")   # => eax
 6878       3d/compare-eax-and 0/imm32/false
 6879       0f 85/jump-if-!= break/disp32
 6880       # if (word-slice == '->') abort
 6881       (slice-equal? %ecx "->")   # => eax
 6882       3d/compare-eax-and 0/imm32/false
 6883       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6884       # if (word-slice == '}') abort
 6885       (slice-equal? %ecx "}")   # => eax
 6886       3d/compare-eax-and 0/imm32/false
 6887       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6888       # v = parse-var-with-type(word-slice, first-line)
 6889       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x14) *(ebp+0x18))
 6890       # assert(var->register != null)
 6891       # . eax: (addr var) = lookup(v)
 6892       (lookup *ebx *(ebx+4))  # => eax
 6893       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 6894       0f 84/jump-if-= $populate-mu-function-header:error3/disp32
 6895       # out->outputs = append(v, out->outputs)
 6896       8d/copy-address *(edi+0x10) 0/r32/eax  # Function-outputs
 6897       (append-list Heap  *ebx *(ebx+4)  *(edi+0x10) *(edi+0x14)  %eax)  # Function-outputs, Function-outputs
 6898       #
 6899       e9/jump loop/disp32
 6900     }
 6901 $populate-mu-function-header:done:
 6902     (check-no-tokens-left *(ebp+8))
 6903 $populate-mu-function-header:end:
 6904     # . reclaim locals
 6905     81 0/subop/add %esp 0x10/imm32
 6906     # . restore registers
 6907     5f/pop-to-edi
 6908     5b/pop-to-ebx
 6909     5a/pop-to-edx
 6910     59/pop-to-ecx
 6911     58/pop-to-eax
 6912     # . epilogue
 6913     89/<- %esp 5/r32/ebp
 6914     5d/pop-to-ebp
 6915     c3/return
 6916 
 6917 $populate-mu-function-header:error1:
 6918     # error("function header not in form 'fn <name> {'")
 6919     (write-buffered *(ebp+0x14) "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '")
 6920     (flush *(ebp+0x14))
 6921     (rewind-stream *(ebp+8))
 6922     (write-stream-data *(ebp+0x14) *(ebp+8))
 6923     (write-buffered *(ebp+0x14) "'\n")
 6924     (flush *(ebp+0x14))
 6925     (stop *(ebp+0x18) 1)
 6926     # never gets here
 6927 
 6928 $populate-mu-function-header:error2:
 6929     # error("fn " fn ": function inout '" var "' cannot be in a register")
 6930     (write-buffered *(ebp+0x14) "fn ")
 6931     50/push-eax
 6932     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 6933     (write-buffered *(ebp+0x14) %eax)
 6934     58/pop-to-eax
 6935     (write-buffered *(ebp+0x14) ": function inout '")
 6936     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 6937     (write-buffered *(ebp+0x10) %eax)
 6938     (write-buffered *(ebp+0x14) "' cannot be in a register")
 6939     (flush *(ebp+0x14))
 6940     (stop *(ebp+0x18) 1)
 6941     # never gets here
 6942 
 6943 $populate-mu-function-header:error3:
 6944     # error("fn " fn ": function output '" var "' must be in a register")
 6945     (write-buffered *(ebp+0x14) "fn ")
 6946     50/push-eax
 6947     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 6948     (write-buffered *(ebp+0x14) %eax)
 6949     58/pop-to-eax
 6950     (write-buffered *(ebp+0x14) ": function output '")
 6951     (lookup *ebx *(ebx+4))  # => eax
 6952     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 6953     (write-buffered *(ebp+0x14) %eax)
 6954     (write-buffered *(ebp+0x14) "' must be in a register, in instruction '")
 6955     (rewind-stream *(ebp+8))
 6956     (write-stream-data *(ebp+0x14) *(ebp+8))
 6957     (write-buffered *(ebp+0x14) "'\n")
 6958     (flush *(ebp+0x14))
 6959     (stop *(ebp+0x18) 1)
 6960     # never gets here
 6961 
 6962 # scenarios considered:
 6963 # ✓ fn foo
 6964 # ✗ fn foo {
 6965 # ✓ fn foo x
 6966 # ✓ fn foo x: int
 6967 # ✓ fn foo x: int -> y/eax: int
 6968 # TODO:
 6969 #   disallow outputs of type `(... addr ...)`
 6970 #   disallow inputs of type `(... addr ... addr ...)`
 6971 populate-mu-function-signature:  # first-line: (addr stream byte), out: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
 6972     # pseudocode:
 6973     #   var word-slice: slice
 6974     #   next-mu-token(first-line, word-slice)
 6975     #   assert(word-slice not in '{' '}' '->')
 6976     #   out->name = slice-to-string(word-slice)
 6977     #   ## inouts
 6978     #   while true
 6979     #     word-slice = next-mu-token(first-line)
 6980     #     if slice-empty?(word-slice) break
 6981     #     if (word-slice == '->') break
 6982     #     assert(word-slice not in '{' '}')
 6983     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 6984     #     assert(v->register == null)
 6985     #     # v->block-depth is implicitly 0
 6986     #     out->inouts = append(v, out->inouts)
 6987     #   ## outputs
 6988     #   while true
 6989     #     word-slice = next-mu-token(first-line)
 6990     #     if slice-empty?(word-slice) break
 6991     #     assert(word-slice not in '{' '}' '->')
 6992     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 6993     #     assert(v->register != null)
 6994     #     out->outputs = append(v, out->outputs)
 6995     #
 6996     # . prologue
 6997     55/push-ebp
 6998     89/<- %ebp 4/r32/esp
 6999     # . save registers
 7000     50/push-eax
 7001     51/push-ecx
 7002     52/push-edx
 7003     53/push-ebx
 7004     57/push-edi
 7005     # edi = out
 7006     8b/-> *(ebp+0xc) 7/r32/edi
 7007     # var word-slice/ecx: slice
 7008     68/push 0/imm32/end
 7009     68/push 0/imm32/start
 7010     89/<- %ecx 4/r32/esp
 7011     # var v/ebx: (handle var)
 7012     68/push 0/imm32
 7013     68/push 0/imm32
 7014     89/<- %ebx 4/r32/esp
 7015     # read function name
 7016     (next-mu-token *(ebp+8) %ecx)
 7017     # error checking
 7018     # if (word-slice == '{') abort
 7019     (slice-equal? %ecx "{")   # => eax
 7020     3d/compare-eax-and 0/imm32/false
 7021     0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7022     # if (word-slice == '->') abort
 7023     (slice-equal? %ecx "->")   # => eax
 7024     3d/compare-eax-and 0/imm32/false
 7025     0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7026     # if (word-slice == '}') abort
 7027     (slice-equal? %ecx "}")   # => eax
 7028     3d/compare-eax-and 0/imm32/false
 7029     0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7030     # save function name
 7031     (slice-to-string Heap %ecx %edi)  # Function-name
 7032     # save function inouts
 7033     {
 7034 $populate-mu-function-signature:check-for-inout:
 7035       (next-mu-token *(ebp+8) %ecx)
 7036       (slice-empty? %ecx)  # => eax
 7037       3d/compare-eax-and 0/imm32/false
 7038       0f 85/jump-if-!= break/disp32
 7039       # if (word-slice == '->') break
 7040       (slice-equal? %ecx "->")   # => eax
 7041       3d/compare-eax-and 0/imm32/false
 7042       0f 85/jump-if-!= break/disp32
 7043       # if (word-slice == '{') abort
 7044       (slice-equal? %ecx "{")   # => eax
 7045       3d/compare-eax-and 0/imm32/false
 7046       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7047       # if (word-slice == '}') abort
 7048       (slice-equal? %ecx "}")   # => eax
 7049       3d/compare-eax-and 0/imm32/false
 7050       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7051       # v = parse-var-with-type(word-slice, first-line)
 7052       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x10) *(ebp+0x14))
 7053       # assert(v->register == null)
 7054       # . eax: (addr var) = lookup(v)
 7055       (lookup *ebx *(ebx+4))  # => eax
 7056       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 7057       0f 85/jump-if-!= $populate-mu-function-signature:error2/disp32
 7058       # v->block-depth is implicitly 0
 7059       #
 7060       # out->inouts = append(v, out->inouts)
 7061       8d/copy-address *(edi+8) 0/r32/eax  # Function-inouts
 7062       (append-list Heap  *ebx *(ebx+4)  *(edi+8) *(edi+0xc)  %eax)  # Function-inouts, Function-inouts
 7063       #
 7064       e9/jump loop/disp32
 7065     }
 7066     # save function outputs
 7067     {
 7068 $populate-mu-function-signature:check-for-out:
 7069       (next-mu-token *(ebp+8) %ecx)
 7070       (slice-empty? %ecx)  # => eax
 7071       3d/compare-eax-and 0/imm32/false
 7072       0f 85/jump-if-!= break/disp32
 7073       # if (word-slice == '{') abort
 7074       (slice-equal? %ecx "{")   # => eax
 7075       3d/compare-eax-and 0/imm32/false
 7076       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7077       # if (word-slice == '->') abort
 7078       (slice-equal? %ecx "->")   # => eax
 7079       3d/compare-eax-and 0/imm32/false
 7080       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7081       # if (word-slice == '}') abort
 7082       (slice-equal? %ecx "}")   # => eax
 7083       3d/compare-eax-and 0/imm32/false
 7084       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7085       # v = parse-var-with-type(word-slice, first-line)
 7086       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x10) *(ebp+0x14))
 7087       # assert(var->register != null)
 7088       # . eax: (addr var) = lookup(v)
 7089       (lookup *ebx *(ebx+4))  # => eax
 7090       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 7091       0f 84/jump-if-= $populate-mu-function-signature:error3/disp32
 7092       # out->outputs = append(v, out->outputs)
 7093       8d/copy-address *(edi+0x10) 0/r32/eax  # Function-outputs
 7094       (append-list Heap  *ebx *(ebx+4)  *(edi+0x10) *(edi+0x14)  %eax)  # Function-outputs, Function-outputs
 7095       #
 7096       e9/jump loop/disp32
 7097     }
 7098 $populate-mu-function-signature:done:
 7099     (check-no-tokens-left *(ebp+8))
 7100 $populate-mu-function-signature:end:
 7101     # . reclaim locals
 7102     81 0/subop/add %esp 0x10/imm32
 7103     # . restore registers
 7104     5f/pop-to-edi
 7105     5b/pop-to-ebx
 7106     5a/pop-to-edx
 7107     59/pop-to-ecx
 7108     58/pop-to-eax
 7109     # . epilogue
 7110     89/<- %esp 5/r32/ebp
 7111     5d/pop-to-ebp
 7112     c3/return
 7113 
 7114 $populate-mu-function-signature:error1:
 7115     # error("function signature not in form 'fn <name> {'")
 7116     (write-buffered *(ebp+0x10) "function signature not in form 'fn <name> [inouts] [-> outputs] {' -- '")
 7117     (flush *(ebp+0x10))
 7118     (rewind-stream *(ebp+8))
 7119     (write-stream-data *(ebp+0x10) *(ebp+8))
 7120     (write-buffered *(ebp+0x10) "'\n")
 7121     (flush *(ebp+0x10))
 7122     (stop *(ebp+0x14) 1)
 7123     # never gets here
 7124 
 7125 $populate-mu-function-signature:error2:
 7126     # error("fn " fn ": function inout '" var "' cannot be in a register")
 7127     (write-buffered *(ebp+0x10) "fn ")
 7128     50/push-eax
 7129     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 7130     (write-buffered *(ebp+0x10) %eax)
 7131     58/pop-to-eax
 7132     (write-buffered *(ebp+0x10) ": function inout '")
 7133     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 7134     (write-buffered *(ebp+0x10) %eax)
 7135     (write-buffered *(ebp+0x10) "' cannot be in a register")
 7136     (flush *(ebp+0x10))
 7137     (stop *(ebp+0x14) 1)
 7138     # never gets here
 7139 
 7140 $populate-mu-function-signature:error3:
 7141     # error("fn " fn ": function output '" var "' must be in a register")
 7142     (write-buffered *(ebp+0x10) "fn ")
 7143     50/push-eax
 7144     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 7145     (write-buffered *(ebp+0x10) %eax)
 7146     58/pop-to-eax
 7147     (write-buffered *(ebp+0x10) ": function output '")
 7148     (lookup *ebx *(ebx+4))  # => eax
 7149     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 7150     (write-buffered *(ebp+0x10) %eax)
 7151     (write-buffered *(ebp+0x10) "' must be in a register, in instruction '")
 7152     (rewind-stream *(ebp+8))
 7153     (write-stream-data *(ebp+0x10) *(ebp+8))
 7154     (write-buffered *(ebp+0x10) "'\n")
 7155     (flush *(ebp+0x10))
 7156     (stop *(ebp+0x14) 1)
 7157     # never gets here
 7158 
 7159 test-function-header-with-arg:
 7160     # . prologue
 7161     55/push-ebp
 7162     89/<- %ebp 4/r32/esp
 7163     # setup
 7164     (clear-stream _test-input-stream)
 7165     (write _test-input-stream "foo n: int {\n")
 7166     # var result/ecx: function
 7167     2b/subtract *Function-size 4/r32/esp
 7168     89/<- %ecx 4/r32/esp
 7169     (zero-out %ecx *Function-size)
 7170     # var vars/ebx: (stack live-var 16)
 7171     81 5/subop/subtract %esp 0xc0/imm32
 7172     68/push 0xc0/imm32/size
 7173     68/push 0/imm32/top
 7174     89/<- %ebx 4/r32/esp
 7175     # convert
 7176     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 7177     # check result->name
 7178     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 7179     (check-strings-equal %eax "foo" "F - test-function-header-with-arg/name")
 7180     # var v/edx: (addr var) = result->inouts->value
 7181     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 7182     (lookup *eax *(eax+4))  # List-value List-value => eax
 7183     89/<- %edx 0/r32/eax
 7184     # check v->name
 7185     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 7186     (check-strings-equal %eax "n" "F - test-function-header-with-arg/inout:0")
 7187     # check v->type
 7188     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 7189     (check-ints-equal *eax 1 "F - test-function-header-with-arg/inout:0/type:0")  # Type-tree-is-atom
 7190     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-arg/inout:0/type:1")  # Type-tree-value
 7191     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-arg/inout:0/type:2")  # Type-tree-right
 7192     # . epilogue
 7193     89/<- %esp 5/r32/ebp
 7194     5d/pop-to-ebp
 7195     c3/return
 7196 
 7197 test-function-header-with-multiple-args:
 7198     # . prologue
 7199     55/push-ebp
 7200     89/<- %ebp 4/r32/esp
 7201     # setup
 7202     (clear-stream _test-input-stream)
 7203     (write _test-input-stream "foo a: int, b: int c: int {\n")
 7204     # result/ecx: function
 7205     2b/subtract *Function-size 4/r32/esp
 7206     89/<- %ecx 4/r32/esp
 7207     (zero-out %ecx *Function-size)
 7208     # var vars/ebx: (stack live-var 16)
 7209     81 5/subop/subtract %esp 0xc0/imm32
 7210     68/push 0xc0/imm32/size
 7211     68/push 0/imm32/top
 7212     89/<- %ebx 4/r32/esp
 7213     # convert
 7214     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 7215     # check result->name
 7216     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 7217     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args/name")
 7218     # var inouts/edx: (addr list var) = lookup(result->inouts)
 7219     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 7220     89/<- %edx 0/r32/eax
 7221 $test-function-header-with-multiple-args:inout0:
 7222     # var v/ebx: (addr var) = lookup(inouts->value)
 7223     (lookup *edx *(edx+4))  # List-value List-value => eax
 7224     89/<- %ebx 0/r32/eax
 7225     # check v->name
 7226     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7227     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args/inout:0")  # Var-name
 7228     # check v->type
 7229     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7230     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:0/type:0")  # Type-tree-is-atom
 7231     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:0/type:1")  # Type-tree-value
 7232     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:0/type:2")  # Type-tree-right
 7233 $test-function-header-with-multiple-args:inout1:
 7234     # inouts = lookup(inouts->next)
 7235     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 7236     89/<- %edx 0/r32/eax
 7237     # v = lookup(inouts->value)
 7238     (lookup *edx *(edx+4))  # List-value List-value => eax
 7239     89/<- %ebx 0/r32/eax
 7240     # check v->name
 7241     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7242     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args/inout:1")  # Var-name
 7243     # check v->type
 7244     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7245     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:1/type:0")  # Type-tree-is-atom
 7246     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:1/type:1")  # Type-tree-value
 7247     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:1/type:2")  # Type-tree-right
 7248 $test-function-header-with-multiple-args:inout2:
 7249     # inouts = lookup(inouts->next)
 7250     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 7251     89/<- %edx 0/r32/eax
 7252     # v = lookup(inouts->value)
 7253     (lookup *edx *(edx+4))  # List-value List-value => eax
 7254     89/<- %ebx 0/r32/eax
 7255     # check v->name
 7256     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7257     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args/inout:2")  # Var-name
 7258     # check v->type
 7259     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7260     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:2/type:0")  # Type-tree-is-atom
 7261     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:2/type:1")  # Type-tree-value
 7262     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:2/type:2")  # Type-tree-right
 7263     # . epilogue
 7264     89/<- %esp 5/r32/ebp
 7265     5d/pop-to-ebp
 7266     c3/return
 7267 
 7268 test-function-header-with-multiple-args-and-outputs:
 7269     # . prologue
 7270     55/push-ebp
 7271     89/<- %ebp 4/r32/esp
 7272     # setup
 7273     (clear-stream _test-input-stream)
 7274     (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx: int {\n")
 7275     # result/ecx: function
 7276     2b/subtract *Function-size 4/r32/esp
 7277     89/<- %ecx 4/r32/esp
 7278     (zero-out %ecx *Function-size)
 7279     # var vars/ebx: (stack live-var 16)
 7280     81 5/subop/subtract %esp 0xc0/imm32
 7281     68/push 0xc0/imm32/size
 7282     68/push 0/imm32/top
 7283     89/<- %ebx 4/r32/esp
 7284     # convert
 7285     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 7286     # check result->name
 7287     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 7288     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args-and-outputs/name")
 7289     # var inouts/edx: (addr list var) = lookup(result->inouts)
 7290     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 7291     89/<- %edx 0/r32/eax
 7292 $test-function-header-with-multiple-args-and-outputs:inout0:
 7293     # var v/ebx: (addr var) = lookup(inouts->value)
 7294     (lookup *edx *(edx+4))  # List-value List-value => eax
 7295     89/<- %ebx 0/r32/eax
 7296     # check v->name
 7297     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7298     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args-and-outputs/inout:0")
 7299     # check v->type
 7300     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7301     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:0")  # Type-tree-is-atom
 7302     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1")  # Type-tree-value
 7303     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:2")  # Type-tree-right
 7304 $test-function-header-with-multiple-args-and-outputs:inout1:
 7305     # inouts = lookup(inouts->next)
 7306     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 7307     89/<- %edx 0/r32/eax
 7308     # v = lookup(inouts->value)
 7309     (lookup *edx *(edx+4))  # List-value List-value => eax
 7310     89/<- %ebx 0/r32/eax
 7311     # check v->name
 7312     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7313     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args-and-outputs/inout:1")
 7314     # check v->type
 7315     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7316     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:0")  # Type-tree-is-atom
 7317     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1")  # Type-tree-value
 7318     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:2")  # Type-tree-right
 7319 $test-function-header-with-multiple-args-and-outputs:inout2:
 7320     # inouts = lookup(inouts->next)
 7321     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 7322     89/<- %edx 0/r32/eax
 7323     # v = lookup(inouts->value)
 7324     (lookup *edx *(edx+4))  # List-value List-value => eax
 7325     89/<- %ebx 0/r32/eax
 7326     # check v->name
 7327     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7328     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args-and-outputs/inout:2")
 7329     # check v->type
 7330     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7331     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:0")  # Type-tree-is-atom
 7332     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1")  # Type-tree-value
 7333     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:2")  # Type-tree-right
 7334 $test-function-header-with-multiple-args-and-outputs:out0:
 7335     # var outputs/edx: (addr list var) = lookup(result->outputs)
 7336     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
 7337     89/<- %edx 0/r32/eax
 7338     # v = lookup(outputs->value)
 7339     (lookup *edx *(edx+4))  # List-value List-value => eax
 7340     89/<- %ebx 0/r32/eax
 7341     # check v->name
 7342     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7343     (check-strings-equal %eax "x" "F - test-function-header-with-multiple-args-and-outputs/output:0")
 7344     # check v->register
 7345     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 7346     (check-strings-equal %eax "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register")
 7347     # check v->type
 7348     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7349     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:0")  # Type-tree-is-atom
 7350     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1")  # Type-tree-value
 7351     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:2")  # Type-tree-right
 7352 $test-function-header-with-multiple-args-and-outputs:out1:
 7353     # outputs = lookup(outputs->next)
 7354     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 7355     89/<- %edx 0/r32/eax
 7356     # v = lookup(inouts->value)
 7357     (lookup *edx *(edx+4))  # List-value List-value => eax
 7358     89/<- %ebx 0/r32/eax
 7359     # check v->name
 7360     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7361     (check-strings-equal %eax "y" "F - test-function-header-with-multiple-args-and-outputs/output:1")
 7362     # check v->register
 7363     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 7364     (check-strings-equal %eax "edx" "F - test-function-header-with-multiple-args-and-outputs/output:1/register")
 7365     # check v->type
 7366     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7367     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:0")  # Type-tree-is-atom
 7368     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1")  # Type-tree-value
 7369     (check-ints-equal *(eax+0c) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:2")  # Type-tree-right
 7370     # . epilogue
 7371     89/<- %esp 5/r32/ebp
 7372     5d/pop-to-ebp
 7373     c3/return
 7374 
 7375 # format for variables with types
 7376 #   x: int
 7377 #   x: int,
 7378 #   x/eax: int
 7379 #   x/eax: int,
 7380 # ignores at most one trailing comma
 7381 # WARNING: modifies name
 7382 parse-var-with-type:  # name: (addr slice), first-line: (addr stream byte), out: (addr handle var), err: (addr buffered-file), ed: (addr exit-descriptor)
 7383     # pseudocode:
 7384     #   var s: slice
 7385     #   if (!slice-ends-with(name, ":"))
 7386     #     abort
 7387     #   --name->end to skip ':'
 7388     #   next-token-from-slice(name->start, name->end, '/', s)
 7389     #   new-var-from-slice(s, out)
 7390     #   ## register
 7391     #   next-token-from-slice(s->end, name->end, '/', s)
 7392     #   if (!slice-empty?(s))
 7393     #     out->register = slice-to-string(s)
 7394     #   ## type
 7395     #   var type: (handle type-tree) = parse-type(first-line)
 7396     #   out->type = type
 7397     #
 7398     # . prologue
 7399     55/push-ebp
 7400     89/<- %ebp 4/r32/esp
 7401     # . save registers
 7402     50/push-eax
 7403     51/push-ecx
 7404     52/push-edx
 7405     53/push-ebx
 7406     56/push-esi
 7407     57/push-edi
 7408     # esi = name
 7409     8b/-> *(ebp+8) 6/r32/esi
 7410     # if (!slice-ends-with?(name, ":")) abort
 7411     8b/-> *(esi+4) 1/r32/ecx  # Slice-end
 7412     49/decrement-ecx
 7413     8a/copy-byte *ecx 1/r32/CL
 7414     81 4/subop/and %ecx 0xff/imm32
 7415     81 7/subop/compare %ecx 0x3a/imm32/colon
 7416     0f 85/jump-if-!= $parse-var-with-type:abort/disp32
 7417     # --name->end to skip ':'
 7418     ff 1/subop/decrement *(esi+4)
 7419     # var s/ecx: slice
 7420     68/push 0/imm32/end
 7421     68/push 0/imm32/start
 7422     89/<- %ecx 4/r32/esp
 7423 $parse-var-with-type:parse-name:
 7424     (next-token-from-slice *esi *(esi+4) 0x2f %ecx)  # Slice-start, Slice-end, '/'
 7425 $parse-var-with-type:create-var:
 7426     # new-var-from-slice(s, out)
 7427     (new-var-from-slice Heap %ecx *(ebp+0x10))
 7428     # save out->register
 7429 $parse-var-with-type:save-register:
 7430     # . var out-addr/edi: (addr var) = lookup(*out)
 7431     8b/-> *(ebp+0x10) 7/r32/edi
 7432     (lookup *edi *(edi+4))  # => eax
 7433     89/<- %edi 0/r32/eax
 7434     # . s = next-token(...)
 7435     (next-token-from-slice *(ecx+4) *(esi+4) 0x2f %ecx)  # s->end, name->end, '/'
 7436     # . if (!slice-empty?(s)) out->register = slice-to-string(s)
 7437     {
 7438 $parse-var-with-type:write-register:
 7439       (slice-empty? %ecx)  # => eax
 7440       3d/compare-eax-and 0/imm32/false
 7441       75/jump-if-!= break/disp8
 7442       # out->register = slice-to-string(s)
 7443       8d/copy-address *(edi+0x18) 0/r32/eax  # Var-register
 7444       (slice-to-string Heap %ecx %eax)
 7445     }
 7446 $parse-var-with-type:save-type:
 7447     8d/copy-address *(edi+8) 0/r32/eax  # Var-type
 7448     (parse-type Heap *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 7449 $parse-var-with-type:end:
 7450     # . reclaim locals
 7451     81 0/subop/add %esp 8/imm32
 7452     # . restore registers
 7453     5f/pop-to-edi
 7454     5e/pop-to-esi
 7455     5b/pop-to-ebx
 7456     5a/pop-to-edx
 7457     59/pop-to-ecx
 7458     58/pop-to-eax
 7459     # . epilogue
 7460     89/<- %esp 5/r32/ebp
 7461     5d/pop-to-ebp
 7462     c3/return
 7463 
 7464 $parse-var-with-type:abort:
 7465     # error("var should have form 'name: type' in '" line "'\n")
 7466     (write-buffered *(ebp+0x14) "var should have form 'name: type' in '")
 7467     (flush *(ebp+0x14))
 7468     (rewind-stream *(ebp+0xc))
 7469     (write-stream-data *(ebp+0x14) *(ebp+0xc))
 7470     (write-buffered *(ebp+0x14) "'\n")
 7471     (flush *(ebp+0x14))
 7472     (stop *(ebp+0x18) 1)
 7473     # never gets here
 7474 
 7475 parse-type:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle type-tree), err: (addr buffered-file), ed: (addr exit-descriptor)
 7476     # pseudocode:
 7477     #   var s: slice = next-mu-token(in)
 7478     #   assert s != ""
 7479     #   assert s != "->"
 7480     #   assert s != "{"
 7481     #   assert s != "}"
 7482     #   if s == ")"
 7483     #     return
 7484     #   out = allocate(Type-tree)
 7485     #   if s != "("
 7486     #     HACK: if s is an int, parse and return it
 7487     #     out->is-atom? = true
 7488     #     if (s[0] == "_")
 7489     #       out->value = type-parameter
 7490     #       out->parameter-name = slice-to-string(ad, s)
 7491     #     else
 7492     #       out->value = pos-or-insert-slice(Type-id, s)
 7493     #     return
 7494     #   out->left = parse-type(ad, in)
 7495     #   out->right = parse-type-tree(ad, in)
 7496     #
 7497     # . prologue
 7498     55/push-ebp
 7499     89/<- %ebp 4/r32/esp
 7500     # . save registers
 7501     50/push-eax
 7502     51/push-ecx
 7503     52/push-edx
 7504     # clear out
 7505     (zero-out *(ebp+0x10) *Handle-size)
 7506     # var s/ecx: slice
 7507     68/push 0/imm32
 7508     68/push 0/imm32
 7509     89/<- %ecx 4/r32/esp
 7510     # s = next-mu-token(in)
 7511     (next-mu-token *(ebp+0xc) %ecx)
 7512 #?     (write-buffered Stderr "tok: ")
 7513 #?     (write-slice-buffered Stderr %ecx)
 7514 #?     (write-buffered Stderr "$\n")
 7515 #?     (flush Stderr)
 7516     # assert s != ""
 7517     (slice-equal? %ecx "")  # => eax
 7518     3d/compare-eax-and 0/imm32/false
 7519     0f 85/jump-if-!= $parse-type:abort/disp32
 7520     # assert s != "{"
 7521     (slice-equal? %ecx "{")  # => eax
 7522     3d/compare-eax-and 0/imm32/false
 7523     0f 85/jump-if-!= $parse-type:abort/disp32
 7524     # assert s != "}"
 7525     (slice-equal? %ecx "}")  # => eax
 7526     3d/compare-eax-and 0/imm32/false
 7527     0f 85/jump-if-!= $parse-type:abort/disp32
 7528     # assert s != "->"
 7529     (slice-equal? %ecx "->")  # => eax
 7530     3d/compare-eax-and 0/imm32/false
 7531     0f 85/jump-if-!= $parse-type:abort/disp32
 7532     # if (s == ")") return
 7533     (slice-equal? %ecx ")")  # => eax
 7534     3d/compare-eax-and 0/imm32/false
 7535     0f 85/jump-if-!= $parse-type:end/disp32
 7536     # out = new tree
 7537     (allocate *(ebp+8) *Type-tree-size *(ebp+0x10))
 7538     # var out-addr/edx: (addr type-tree) = lookup(*out)
 7539     8b/-> *(ebp+0x10) 2/r32/edx
 7540     (lookup *edx *(edx+4))  # => eax
 7541     89/<- %edx 0/r32/eax
 7542     {
 7543       # if (s != "(") break
 7544       (slice-equal? %ecx "(")  # => eax
 7545       3d/compare-eax-and 0/imm32/false
 7546       0f 85/jump-if-!= break/disp32
 7547       # if s is a number, store it in the type's size field
 7548       {
 7549 $parse-type:check-for-int:
 7550         # var tmp/eax: byte = *s->slice
 7551         8b/-> *ecx 0/r32/eax
 7552         8a/copy-byte *eax 0/r32/AL
 7553         81 4/subop/and %eax 0xff/imm32
 7554         # TODO: raise an error on `var x: (array int a)`
 7555         (is-decimal-digit? %eax)  # => eax
 7556         3d/compare-eax-and 0/imm32/false
 7557         74/jump-if-= break/disp8
 7558         #
 7559         (is-hex-int? %ecx)  # => eax
 7560         3d/compare-eax-and 0/imm32/false
 7561         74/jump-if-= break/disp8
 7562 $parse-type:int:
 7563         (check-mu-hex-int %ecx *(ebp+0x14) *(ebp+0x18))
 7564         (parse-hex-int-from-slice %ecx)  # => eax
 7565         c7 0/subop/copy *(edx+4) 9/imm32/type-id-array-capacity  # Type-tree-value
 7566         89/<- *(edx+8) 0/r32/eax  # Type-tree-value-size
 7567         e9/jump $parse-type:end/disp32
 7568       }
 7569 $parse-type:atom:
 7570       # out->is-atom? = true
 7571       c7 0/subop/copy *edx 1/imm32/true  # Type-tree-is-atom
 7572       {
 7573 $parse-type:check-for-type-parameter:
 7574         # var tmp/eax: byte = *s->slice
 7575         8b/-> *ecx 0/r32/eax
 7576         8a/copy-byte *eax 0/r32/AL
 7577         81 4/subop/and %eax 0xff/imm32
 7578         # if (tmp != '_') break
 7579         3d/compare-eax-and 0x5f/imm32/_
 7580         75/jump-if-!= break/disp8
 7581 $parse-type:type-parameter:
 7582         # out->value = type-parameter
 7583         c7 0/subop/copy *(edx+4) 0xa/imm32/type-parameter  # Type-tree-value
 7584         # out->parameter-name = slice-to-string(ad, s)
 7585         8d/copy-address *(edx+8) 0/r32/eax  # Type-tree-parameter-name
 7586         (slice-to-string *(ebp+8) %ecx %eax)
 7587         e9/jump $parse-type:end/disp32
 7588       }
 7589 $parse-type:non-type-parameter:
 7590       # out->value = pos-or-insert-slice(Type-id, s)
 7591       (pos-or-insert-slice Type-id %ecx)  # => eax
 7592       89/<- *(edx+4) 0/r32/eax  # Type-tree-value
 7593       e9/jump $parse-type:end/disp32
 7594     }
 7595 $parse-type:non-atom:
 7596     # otherwise s == "("
 7597     # out->left = parse-type(ad, in)
 7598     8d/copy-address *(edx+4) 0/r32/eax  # Type-tree-left
 7599     (parse-type *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 7600     # out->right = parse-type-tree(ad, in)
 7601     8d/copy-address *(edx+0xc) 0/r32/eax  # Type-tree-right
 7602     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 7603 $parse-type:end:
 7604     # . reclaim locals
 7605     81 0/subop/add %esp 8/imm32
 7606     # . restore registers
 7607     5a/pop-to-edx
 7608     59/pop-to-ecx
 7609     58/pop-to-eax
 7610     # . epilogue
 7611     89/<- %esp 5/r32/ebp
 7612     5d/pop-to-ebp
 7613     c3/return
 7614 
 7615 $parse-type:abort:
 7616     # error("unexpected token when parsing type: '" s "'\n")
 7617     (write-buffered *(ebp+0x14) "unexpected token when parsing type: '")
 7618     (write-slice-buffered *(ebp+0x14) %ecx)
 7619     (write-buffered *(ebp+0x14) "'\n")
 7620     (flush *(ebp+0x14))
 7621     (stop *(ebp+0x18) 1)
 7622     # never gets here
 7623 
 7624 parse-type-tree:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle type-tree), err: (addr buffered-file), ed: (addr exit-descriptor)
 7625     # pseudocode:
 7626     #   var tmp: (handle type-tree) = parse-type(ad, in)
 7627     #   if tmp == 0
 7628     #     return 0
 7629     #   out = allocate(Type-tree)
 7630     #   out->left = tmp
 7631     #   out->right = parse-type-tree(ad, in)
 7632     #
 7633     # . prologue
 7634     55/push-ebp
 7635     89/<- %ebp 4/r32/esp
 7636     # . save registers
 7637     50/push-eax
 7638     51/push-ecx
 7639     52/push-edx
 7640     #
 7641     (zero-out *(ebp+0x10) *Handle-size)
 7642     # var tmp/ecx: (handle type-tree)
 7643     68/push 0/imm32
 7644     68/push 0/imm32
 7645     89/<- %ecx 4/r32/esp
 7646     # tmp = parse-type(ad, in)
 7647     (parse-type *(ebp+8) *(ebp+0xc) %ecx *(ebp+0x14) *(ebp+0x18))
 7648     # if (tmp == 0) return
 7649     81 7/subop/compare *ecx 0/imm32
 7650     74/jump-if-= $parse-type-tree:end/disp8
 7651     # out = new tree
 7652     (allocate *(ebp+8) *Type-tree-size *(ebp+0x10))
 7653     # var out-addr/edx: (addr tree) = lookup(*out)
 7654     8b/-> *(ebp+0x10) 2/r32/edx
 7655     (lookup *edx *(edx+4))  # => eax
 7656     89/<- %edx 0/r32/eax
 7657     # out->left = tmp
 7658     8b/-> *ecx 0/r32/eax
 7659     89/<- *(edx+4) 0/r32/eax  # Type-tree-left
 7660     8b/-> *(ecx+4) 0/r32/eax
 7661     89/<- *(edx+8) 0/r32/eax  # Type-tree-left
 7662     # out->right = parse-type-tree(ad, in)
 7663     8d/copy-address *(edx+0xc) 0/r32/eax  # Type-tree-right
 7664     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 7665 $parse-type-tree:end:
 7666     # . reclaim locals
 7667     81 0/subop/add %esp 8/imm32
 7668     # . restore registers
 7669     5a/pop-to-edx
 7670     59/pop-to-ecx
 7671     58/pop-to-eax
 7672     # . epilogue
 7673     89/<- %esp 5/r32/ebp
 7674     5d/pop-to-ebp
 7675     c3/return
 7676 
 7677 next-mu-token:  # in: (addr stream byte), out: (addr slice)
 7678     # pseudocode:
 7679     # start:
 7680     #   skip-chars-matching-whitespace(in)
 7681     #   if in->read >= in->write              # end of in
 7682     #     out = {0, 0}
 7683     #     return
 7684     #   out->start = &in->data[in->read]
 7685     #   var curr-byte/eax: byte = in->data[in->read]
 7686     #   if curr->byte == ','                  # comment token
 7687     #     ++in->read
 7688     #     goto start
 7689     #   if curr-byte == '#'                   # comment
 7690     #     goto done                             # treat as eof
 7691     #   if curr-byte == '"'                   # string literal
 7692     #     skip-string(in)
 7693     #     goto done                           # no metadata
 7694     #   if curr-byte == '('
 7695     #     ++in->read
 7696     #     goto done
 7697     #   if curr-byte == ')'
 7698     #     ++in->read
 7699     #     goto done
 7700     #   # read a word
 7701     #   while true
 7702     #     if in->read >= in->write
 7703     #       break
 7704     #     curr-byte = in->data[in->read]
 7705     #     if curr-byte == ' '
 7706     #       break
 7707     #     if curr-byte == '\r'
 7708     #       break
 7709     #     if curr-byte == '\n'
 7710     #       break
 7711     #     if curr-byte == '('
 7712     #       break
 7713     #     if curr-byte == ')'
 7714     #       break
 7715     #     if curr-byte == ','
 7716     #       break
 7717     #     ++in->read
 7718     # done:
 7719     #   out->end = &in->data[in->read]
 7720     #
 7721     # . prologue
 7722     55/push-ebp
 7723     89/<- %ebp 4/r32/esp
 7724     # . save registers
 7725     50/push-eax
 7726     51/push-ecx
 7727     56/push-esi
 7728     57/push-edi
 7729     # esi = in
 7730     8b/-> *(ebp+8) 6/r32/esi
 7731     # edi = out
 7732     8b/-> *(ebp+0xc) 7/r32/edi
 7733 $next-mu-token:start:
 7734     (skip-chars-matching-whitespace %esi)
 7735 $next-mu-token:check0:
 7736     # if (in->read >= in->write) return out = {0, 0}
 7737     # . ecx = in->read
 7738     8b/-> *(esi+4) 1/r32/ecx
 7739     # . if (ecx >= in->write) return out = {0, 0}
 7740     3b/compare<- *esi 1/r32/ecx
 7741     c7 0/subop/copy *edi 0/imm32
 7742     c7 0/subop/copy *(edi+4) 0/imm32
 7743     0f 8d/jump-if->= $next-mu-token:end/disp32
 7744     # out->start = &in->data[in->read]
 7745     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
 7746     89/<- *edi 0/r32/eax
 7747     # var curr-byte/eax: byte = in->data[in->read]
 7748     31/xor-with %eax 0/r32/eax
 7749     8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
 7750     {
 7751 $next-mu-token:check-for-comma:
 7752       # if (curr-byte != ',') break
 7753       3d/compare-eax-and 0x2c/imm32/comma
 7754       75/jump-if-!= break/disp8
 7755       # ++in->read
 7756       ff 0/subop/increment *(esi+4)
 7757       # restart
 7758       e9/jump $next-mu-token:start/disp32
 7759     }
 7760     {
 7761 $next-mu-token:check-for-comment:
 7762       # if (curr-byte != '#') break
 7763       3d/compare-eax-and 0x23/imm32/pound
 7764       75/jump-if-!= break/disp8
 7765       # return eof
 7766       e9/jump $next-mu-token:done/disp32
 7767     }
 7768     {
 7769 $next-mu-token:check-for-string-literal:
 7770       # if (curr-byte != '"') break
 7771       3d/compare-eax-and 0x22/imm32/dquote
 7772       75/jump-if-!= break/disp8
 7773       (skip-string %esi)
 7774       # return
 7775       e9/jump $next-mu-token:done/disp32
 7776     }
 7777     {
 7778 $next-mu-token:check-for-open-paren:
 7779       # if (curr-byte != '(') break
 7780       3d/compare-eax-and 0x28/imm32/open-paren
 7781       75/jump-if-!= break/disp8
 7782       # ++in->read
 7783       ff 0/subop/increment *(esi+4)
 7784       # return
 7785       e9/jump $next-mu-token:done/disp32
 7786     }
 7787     {
 7788 $next-mu-token:check-for-close-paren:
 7789       # if (curr-byte != ')') break
 7790       3d/compare-eax-and 0x29/imm32/close-paren
 7791       75/jump-if-!= break/disp8
 7792       # ++in->read
 7793       ff 0/subop/increment *(esi+4)
 7794       # return
 7795       e9/jump $next-mu-token:done/disp32
 7796     }
 7797     {
 7798 $next-mu-token:regular-word-without-metadata:
 7799       # if (in->read >= in->write) break
 7800       # . ecx = in->read
 7801       8b/-> *(esi+4) 1/r32/ecx
 7802       # . if (ecx >= in->write) break
 7803       3b/compare<- *esi 1/r32/ecx
 7804       7d/jump-if->= break/disp8
 7805       # var c/eax: byte = in->data[in->read]
 7806       31/xor-with %eax 0/r32/eax
 7807       8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
 7808       # if (c == ' ') break
 7809       3d/compare-eax-and 0x20/imm32/space
 7810       74/jump-if-= break/disp8
 7811       # if (c == '\r') break
 7812       3d/compare-eax-and 0xd/imm32/carriage-return
 7813       74/jump-if-= break/disp8
 7814       # if (c == '\n') break
 7815       3d/compare-eax-and 0xa/imm32/newline
 7816       74/jump-if-= break/disp8
 7817       # if (c == '(') break
 7818       3d/compare-eax-and 0x28/imm32/open-paren
 7819       0f 84/jump-if-= break/disp32
 7820       # if (c == ')') break
 7821       3d/compare-eax-and 0x29/imm32/close-paren
 7822       0f 84/jump-if-= break/disp32
 7823       # if (c == ',') break
 7824       3d/compare-eax-and 0x2c/imm32/comma
 7825       0f 84/jump-if-= break/disp32
 7826       # ++in->read
 7827       ff 0/subop/increment *(esi+4)
 7828       #
 7829       e9/jump loop/disp32
 7830     }
 7831 $next-mu-token:done:
 7832     # out->end = &in->data[in->read]
 7833     8b/-> *(esi+4) 1/r32/ecx
 7834     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
 7835     89/<- *(edi+4) 0/r32/eax
 7836 $next-mu-token:end:
 7837     # . restore registers
 7838     5f/pop-to-edi
 7839     5e/pop-to-esi
 7840     59/pop-to-ecx
 7841     58/pop-to-eax
 7842     # . epilogue
 7843     89/<- %esp 5/r32/ebp
 7844     5d/pop-to-ebp
 7845     c3/return
 7846 
 7847 pos-or-insert-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
 7848     # . prologue
 7849     55/push-ebp
 7850     89/<- %ebp 4/r32/esp
 7851     # if (pos-slice(arr, s) != -1) return it
 7852     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
 7853     3d/compare-eax-and -1/imm32
 7854     75/jump-if-!= $pos-or-insert-slice:end/disp8
 7855 $pos-or-insert-slice:insert:
 7856     # var s2/eax: (handle array byte)
 7857     68/push 0/imm32
 7858     68/push 0/imm32
 7859     89/<- %eax 4/r32/esp
 7860     (slice-to-string Heap *(ebp+0xc) %eax)
 7861     # throw away alloc-id
 7862     (lookup *eax *(eax+4))  # => eax
 7863     (write-int *(ebp+8) %eax)
 7864     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
 7865 $pos-or-insert-slice:end:
 7866     # . reclaim locals
 7867     81 0/subop/add %esp 8/imm32
 7868     # . epilogue
 7869     89/<- %esp 5/r32/ebp
 7870     5d/pop-to-ebp
 7871     c3/return
 7872 
 7873 # return the index in an array of strings matching 's', -1 if not found
 7874 # index is denominated in elements, not bytes
 7875 pos-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
 7876     # . prologue
 7877     55/push-ebp
 7878     89/<- %ebp 4/r32/esp
 7879     # . save registers
 7880     51/push-ecx
 7881     52/push-edx
 7882     53/push-ebx
 7883     56/push-esi
 7884 #?     (write-buffered Stderr "pos-slice: ")
 7885 #?     (write-slice-buffered Stderr *(ebp+0xc))
 7886 #?     (write-buffered Stderr "\n")
 7887 #?     (flush Stderr)
 7888     # esi = arr
 7889     8b/-> *(ebp+8) 6/r32/esi
 7890     # var index/ecx: int = 0
 7891     b9/copy-to-ecx 0/imm32
 7892     # var curr/edx: (addr (addr array byte)) = arr->data
 7893     8d/copy-address *(esi+0xc) 2/r32/edx
 7894     # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write]
 7895     8b/-> *esi 3/r32/ebx
 7896     8d/copy-address *(esi+ebx+0xc) 3/r32/ebx
 7897     {
 7898 #?       (write-buffered Stderr "  ")
 7899 #?       (write-int32-hex-buffered Stderr %ecx)
 7900 #?       (write-buffered Stderr "\n")
 7901 #?       (flush Stderr)
 7902       # if (curr >= max) return -1
 7903       39/compare %edx 3/r32/ebx
 7904       b8/copy-to-eax -1/imm32
 7905       73/jump-if-addr>= $pos-slice:end/disp8
 7906       # if (slice-equal?(s, *curr)) break
 7907       (slice-equal? *(ebp+0xc) *edx)  # => eax
 7908       3d/compare-eax-and 0/imm32/false
 7909       75/jump-if-!= break/disp8
 7910       # ++index
 7911       41/increment-ecx
 7912       # curr += 4
 7913       81 0/subop/add %edx 4/imm32
 7914       #
 7915       eb/jump loop/disp8
 7916     }
 7917     # return index
 7918     89/<- %eax 1/r32/ecx
 7919 $pos-slice:end:
 7920 #?     (write-buffered Stderr "=> ")
 7921 #?     (write-int32-hex-buffered Stderr %eax)
 7922 #?     (write-buffered Stderr "\n")
 7923     # . restore registers
 7924     5e/pop-to-esi
 7925     5b/pop-to-ebx
 7926     5a/pop-to-edx
 7927     59/pop-to-ecx
 7928     # . epilogue
 7929     89/<- %esp 5/r32/ebp
 7930     5d/pop-to-ebp
 7931     c3/return
 7932 
 7933 test-parse-var-with-type:
 7934     # . prologue
 7935     55/push-ebp
 7936     89/<- %ebp 4/r32/esp
 7937     # (eax..ecx) = "x:"
 7938     b8/copy-to-eax "x:"/imm32
 7939     8b/-> *eax 1/r32/ecx
 7940     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7941     05/add-to-eax 4/imm32
 7942     # var slice/ecx: slice = {eax, ecx}
 7943     51/push-ecx
 7944     50/push-eax
 7945     89/<- %ecx 4/r32/esp
 7946     # _test-input-stream contains "int"
 7947     (clear-stream _test-input-stream)
 7948     (write _test-input-stream "int")
 7949     # var v/edx: (handle var)
 7950     68/push 0/imm32
 7951     68/push 0/imm32
 7952     89/<- %edx 4/r32/esp
 7953     #
 7954     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 7955     # var v-addr/edx: (addr var) = lookup(v)
 7956     (lookup *edx *(edx+4))  # => eax
 7957     89/<- %edx 0/r32/eax
 7958     # check v-addr->name
 7959     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 7960     (check-strings-equal %eax "x" "F - test-parse-var-with-type/name")
 7961     # check v-addr->type
 7962     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 7963     (check-ints-equal *eax 1 "F - test-parse-var-with-type/type:0")  # Type-tree-is-atom
 7964     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type/type:1")  # Type-tree-value
 7965     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type/type:2")  # Type-tree-right
 7966     # . epilogue
 7967     89/<- %esp 5/r32/ebp
 7968     5d/pop-to-ebp
 7969     c3/return
 7970 
 7971 test-parse-var-with-type-and-register:
 7972     # . prologue
 7973     55/push-ebp
 7974     89/<- %ebp 4/r32/esp
 7975     # (eax..ecx) = "x/eax:"
 7976     b8/copy-to-eax "x/eax:"/imm32
 7977     8b/-> *eax 1/r32/ecx
 7978     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7979     05/add-to-eax 4/imm32
 7980     # var slice/ecx: slice = {eax, ecx}
 7981     51/push-ecx
 7982     50/push-eax
 7983     89/<- %ecx 4/r32/esp
 7984     # _test-input-stream contains "int"
 7985     (clear-stream _test-input-stream)
 7986     (write _test-input-stream "int")
 7987     # var v/edx: (handle var)
 7988     68/push 0/imm32
 7989     68/push 0/imm32
 7990     89/<- %edx 4/r32/esp
 7991     #
 7992     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 7993     # var v-addr/edx: (addr var) = lookup(v)
 7994     (lookup *edx *(edx+4))  # => eax
 7995     89/<- %edx 0/r32/eax
 7996     # check v-addr->name
 7997     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 7998     (check-strings-equal %eax "x" "F - test-parse-var-with-type-and-register/name")
 7999     # check v-addr->register
 8000     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 8001     (check-strings-equal %eax "eax" "F - test-parse-var-with-type-and-register/register")
 8002     # check v-addr->type
 8003     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 8004     (check-ints-equal *eax 1 "F - test-parse-var-with-type-and-register/type:0")  # Type-tree-is-atom
 8005     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type-and-register/type:1")  # Type-tree-left
 8006     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type-and-register/type:2")  # Type-tree-right
 8007     # . epilogue
 8008     89/<- %esp 5/r32/ebp
 8009     5d/pop-to-ebp
 8010     c3/return
 8011 
 8012 test-parse-var-with-trailing-characters:
 8013     # . prologue
 8014     55/push-ebp
 8015     89/<- %ebp 4/r32/esp
 8016     # (eax..ecx) = "x:"
 8017     b8/copy-to-eax "x:"/imm32
 8018     8b/-> *eax 1/r32/ecx
 8019     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8020     05/add-to-eax 4/imm32
 8021     # var slice/ecx: slice = {eax, ecx}
 8022     51/push-ecx
 8023     50/push-eax
 8024     89/<- %ecx 4/r32/esp
 8025     # _test-input-stream contains "int,"
 8026     (clear-stream _test-input-stream)
 8027     (write _test-input-stream "int,")
 8028     # var v/edx: (handle var)
 8029     68/push 0/imm32
 8030     68/push 0/imm32
 8031     89/<- %edx 4/r32/esp
 8032     #
 8033     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 8034     # var v-addr/edx: (addr var) = lookup(v)
 8035     (lookup *edx *(edx+4))  # => eax
 8036     89/<- %edx 0/r32/eax
 8037     # check v-addr->name
 8038     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 8039     (check-strings-equal %eax "x" "F - test-parse-var-with-trailing-characters/name")
 8040     # check v-addr->register
 8041     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-trailing-characters/register")  # Var-register
 8042     # check v-addr->type
 8043     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 8044     (check-ints-equal *eax 1 "F - test-parse-var-with-trailing-characters/type:0")  # Type-tree-is-atom
 8045     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-trailing-characters/type:1")  # Type-tree-left
 8046     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-trailing-characters/type:1")  # Type-tree-right
 8047     # . epilogue
 8048     89/<- %esp 5/r32/ebp
 8049     5d/pop-to-ebp
 8050     c3/return
 8051 
 8052 test-parse-var-with-register-and-trailing-characters:
 8053     # . prologue
 8054     55/push-ebp
 8055     89/<- %ebp 4/r32/esp
 8056     # (eax..ecx) = "x/eax:"
 8057     b8/copy-to-eax "x/eax:"/imm32
 8058     8b/-> *eax 1/r32/ecx
 8059     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8060     05/add-to-eax 4/imm32
 8061     # var slice/ecx: slice = {eax, ecx}
 8062     51/push-ecx
 8063     50/push-eax
 8064     89/<- %ecx 4/r32/esp
 8065     # _test-input-stream contains "int,"
 8066     (clear-stream _test-input-stream)
 8067     (write _test-input-stream "int,")
 8068     # var v/edx: (handle var)
 8069     68/push 0/imm32
 8070     68/push 0/imm32
 8071     89/<- %edx 4/r32/esp
 8072     #
 8073     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 8074     # var v-addr/edx: (addr var) = lookup(v)
 8075     (lookup *edx *(edx+4))  # => eax
 8076     89/<- %edx 0/r32/eax
 8077     # check v-addr->name
 8078     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 8079     (check-strings-equal %eax "x" "F - test-parse-var-with-register-and-trailing-characters/name")
 8080     # check v-addr->register
 8081     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 8082     (check-strings-equal %eax "eax" "F - test-parse-var-with-register-and-trailing-characters/register")
 8083     # check v-addr->type
 8084     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 8085     (check-ints-equal *eax 1 "F - test-parse-var-with-register-and-trailing-characters/type:0")  # Type-tree-is-atom
 8086     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-register-and-trailing-characters/type:1")  # Type-tree-left
 8087     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-register-and-trailing-characters/type:2")  # Type-tree-right
 8088     # . epilogue
 8089     89/<- %esp 5/r32/ebp
 8090     5d/pop-to-ebp
 8091     c3/return
 8092 
 8093 test-parse-var-with-compound-type:
 8094     # . prologue
 8095     55/push-ebp
 8096     89/<- %ebp 4/r32/esp
 8097     # (eax..ecx) = "x:"
 8098     b8/copy-to-eax "x:"/imm32
 8099     8b/-> *eax 1/r32/ecx
 8100     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8101     05/add-to-eax 4/imm32
 8102     # var slice/ecx: slice = {eax, ecx}
 8103     51/push-ecx
 8104     50/push-eax
 8105     89/<- %ecx 4/r32/esp
 8106     # _test-input-stream contains "(addr int)"
 8107     (clear-stream _test-input-stream)
 8108     (write _test-input-stream "(addr int)")
 8109     # var v/edx: (handle var)
 8110     68/push 0/imm32
 8111     68/push 0/imm32
 8112     89/<- %edx 4/r32/esp
 8113     #
 8114     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 8115     # var v-addr/edx: (addr var) = lookup(v)
 8116     (lookup *edx *(edx+4))  # => eax
 8117     89/<- %edx 0/r32/eax
 8118     # check v-addr->name
 8119     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 8120     (check-strings-equal %eax "x" "F - test-parse-var-with-compound-type/name")
 8121     # check v-addr->register
 8122     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-compound-type/register")  # Var-register
 8123     # - check v-addr->type
 8124     # var type/edx: (addr type-tree) = var->type
 8125     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 8126     89/<- %edx 0/r32/eax
 8127     # type is a non-atom
 8128     (check-ints-equal *edx 0 "F - test-parse-var-with-compound-type/type:0")  # Type-tree-is-atom
 8129     # type->left == atom(addr)
 8130     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
 8131     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:1")  # Type-tree-is-atom
 8132     (check-ints-equal *(eax+4) 2 "F - test-parse-var-with-compound-type/type:2")  # Type-tree-value
 8133     # type->right->left == atom(int)
 8134     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
 8135     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
 8136     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:3")  # Type-tree-is-atom
 8137     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-compound-type/type:4")  # Type-tree-value
 8138     # type->right->right == null
 8139     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-compound-type/type:5")  # Type-tree-right
 8140     # . epilogue
 8141     89/<- %esp 5/r32/ebp
 8142     5d/pop-to-ebp
 8143     c3/return
 8144 
 8145 # identifier starts with a letter or '$' or '_'
 8146 # no constraints at the moment on later letters
 8147 # all we really want to do so far is exclude '{', '}' and '->'
 8148 is-identifier?:  # in: (addr slice) -> result/eax: boolean
 8149     # . prologue
 8150     55/push-ebp
 8151     89/<- %ebp 4/r32/esp
 8152     # if (slice-empty?(in)) return false
 8153     (slice-empty? *(ebp+8))  # => eax
 8154     3d/compare-eax-and 0/imm32/false
 8155     75/jump-if-!= $is-identifier?:false/disp8
 8156     # var c/eax: byte = *in->start
 8157     8b/-> *(ebp+8) 0/r32/eax
 8158     8b/-> *eax 0/r32/eax
 8159     8a/copy-byte *eax 0/r32/AL
 8160     81 4/subop/and %eax 0xff/imm32
 8161     # if (c == '$') return true
 8162     3d/compare-eax-and 0x24/imm32/$
 8163     74/jump-if-= $is-identifier?:true/disp8
 8164     # if (c == '_') return true
 8165     3d/compare-eax-and 0x5f/imm32/_
 8166     74/jump-if-= $is-identifier?:true/disp8
 8167     # drop case
 8168     25/and-eax-with 0x5f/imm32
 8169     # if (c < 'A') return false
 8170     3d/compare-eax-and 0x41/imm32/A
 8171     7c/jump-if-< $is-identifier?:false/disp8
 8172     # if (c > 'Z') return false
 8173     3d/compare-eax-and 0x5a/imm32/Z
 8174     7f/jump-if-> $is-identifier?:false/disp8
 8175     # otherwise return true
 8176 $is-identifier?:true:
 8177     b8/copy-to-eax 1/imm32/true
 8178     eb/jump $is-identifier?:end/disp8
 8179 $is-identifier?:false:
 8180     b8/copy-to-eax 0/imm32/false
 8181 $is-identifier?:end:
 8182     # . epilogue
 8183     89/<- %esp 5/r32/ebp
 8184     5d/pop-to-ebp
 8185     c3/return
 8186 
 8187 test-is-identifier-dollar:
 8188     # . prologue
 8189     55/push-ebp
 8190     89/<- %ebp 4/r32/esp
 8191     # (eax..ecx) = "$a"
 8192     b8/copy-to-eax "$a"/imm32
 8193     8b/-> *eax 1/r32/ecx
 8194     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8195     05/add-to-eax 4/imm32
 8196     # var slice/ecx: slice = {eax, ecx}
 8197     51/push-ecx
 8198     50/push-eax
 8199     89/<- %ecx 4/r32/esp
 8200     #
 8201     (is-identifier? %ecx)
 8202     (check-ints-equal %eax 1 "F - test-is-identifier-dollar")
 8203     # . epilogue
 8204     89/<- %esp 5/r32/ebp
 8205     5d/pop-to-ebp
 8206     c3/return
 8207 
 8208 test-is-identifier-underscore:
 8209     # . prologue
 8210     55/push-ebp
 8211     89/<- %ebp 4/r32/esp
 8212     # (eax..ecx) = "_a"
 8213     b8/copy-to-eax "_a"/imm32
 8214     8b/-> *eax 1/r32/ecx
 8215     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8216     05/add-to-eax 4/imm32
 8217     # var slice/ecx: slice = {eax, ecx}
 8218     51/push-ecx
 8219     50/push-eax
 8220     89/<- %ecx 4/r32/esp
 8221     #
 8222     (is-identifier? %ecx)
 8223     (check-ints-equal %eax 1 "F - test-is-identifier-underscore")
 8224     # . epilogue
 8225     89/<- %esp 5/r32/ebp
 8226     5d/pop-to-ebp
 8227     c3/return
 8228 
 8229 test-is-identifier-a:
 8230     # . prologue
 8231     55/push-ebp
 8232     89/<- %ebp 4/r32/esp
 8233     # (eax..ecx) = "a$"
 8234     b8/copy-to-eax "a$"/imm32
 8235     8b/-> *eax 1/r32/ecx
 8236     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8237     05/add-to-eax 4/imm32
 8238     # var slice/ecx: slice = {eax, ecx}
 8239     51/push-ecx
 8240     50/push-eax
 8241     89/<- %ecx 4/r32/esp
 8242     #
 8243     (is-identifier? %ecx)
 8244     (check-ints-equal %eax 1 "F - test-is-identifier-a")
 8245     # . epilogue
 8246     89/<- %esp 5/r32/ebp
 8247     5d/pop-to-ebp
 8248     c3/return
 8249 
 8250 test-is-identifier-z:
 8251     # . prologue
 8252     55/push-ebp
 8253     89/<- %ebp 4/r32/esp
 8254     # (eax..ecx) = "z$"
 8255     b8/copy-to-eax "z$"/imm32
 8256     8b/-> *eax 1/r32/ecx
 8257     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8258     05/add-to-eax 4/imm32
 8259     # var slice/ecx: slice = {eax, ecx}
 8260     51/push-ecx
 8261     50/push-eax
 8262     89/<- %ecx 4/r32/esp
 8263     #
 8264     (is-identifier? %ecx)
 8265     (check-ints-equal %eax 1 "F - test-is-identifier-z")
 8266     # . epilogue
 8267     89/<- %esp 5/r32/ebp
 8268     5d/pop-to-ebp
 8269     c3/return
 8270 
 8271 test-is-identifier-A:
 8272     # . prologue
 8273     55/push-ebp
 8274     89/<- %ebp 4/r32/esp
 8275     # (eax..ecx) = "A$"
 8276     b8/copy-to-eax "A$"/imm32
 8277     8b/-> *eax 1/r32/ecx
 8278     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8279     05/add-to-eax 4/imm32
 8280     # var slice/ecx: slice = {eax, ecx}
 8281     51/push-ecx
 8282     50/push-eax
 8283     89/<- %ecx 4/r32/esp
 8284     #
 8285     (is-identifier? %ecx)
 8286     (check-ints-equal %eax 1 "F - test-is-identifier-A")
 8287     # . epilogue
 8288     89/<- %esp 5/r32/ebp
 8289     5d/pop-to-ebp
 8290     c3/return
 8291 
 8292 test-is-identifier-Z:
 8293     # . prologue
 8294     55/push-ebp
 8295     89/<- %ebp 4/r32/esp
 8296     # (eax..ecx) = "Z$"
 8297     b8/copy-to-eax "Z$"/imm32
 8298     8b/-> *eax 1/r32/ecx
 8299     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8300     05/add-to-eax 4/imm32
 8301     # var slice/ecx: slice = {eax, ecx}
 8302     51/push-ecx
 8303     50/push-eax
 8304     89/<- %ecx 4/r32/esp
 8305     #
 8306     (is-identifier? %ecx)
 8307     (check-ints-equal %eax 1 "F - test-is-identifier-Z")
 8308     # . epilogue
 8309     89/<- %esp 5/r32/ebp
 8310     5d/pop-to-ebp
 8311     c3/return
 8312 
 8313 test-is-identifier-at:
 8314     # character before 'A' is invalid
 8315     # . prologue
 8316     55/push-ebp
 8317     89/<- %ebp 4/r32/esp
 8318     # (eax..ecx) = "@a"
 8319     b8/copy-to-eax "@a"/imm32
 8320     8b/-> *eax 1/r32/ecx
 8321     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8322     05/add-to-eax 4/imm32
 8323     # var slice/ecx: slice = {eax, ecx}
 8324     51/push-ecx
 8325     50/push-eax
 8326     89/<- %ecx 4/r32/esp
 8327     #
 8328     (is-identifier? %ecx)
 8329     (check-ints-equal %eax 0 "F - test-is-identifier-@")
 8330     # . epilogue
 8331     89/<- %esp 5/r32/ebp
 8332     5d/pop-to-ebp
 8333     c3/return
 8334 
 8335 test-is-identifier-square-bracket:
 8336     # character after 'Z' is invalid
 8337     # . prologue
 8338     55/push-ebp
 8339     89/<- %ebp 4/r32/esp
 8340     # (eax..ecx) = "[a"
 8341     b8/copy-to-eax "[a"/imm32
 8342     8b/-> *eax 1/r32/ecx
 8343     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8344     05/add-to-eax 4/imm32
 8345     # var slice/ecx: slice = {eax, ecx}
 8346     51/push-ecx
 8347     50/push-eax
 8348     89/<- %ecx 4/r32/esp
 8349     #
 8350     (is-identifier? %ecx)
 8351     (check-ints-equal %eax 0 "F - test-is-identifier-@")
 8352     # . epilogue
 8353     89/<- %esp 5/r32/ebp
 8354     5d/pop-to-ebp
 8355     c3/return
 8356 
 8357 test-is-identifier-backtick:
 8358     # character before 'a' is invalid
 8359     # . prologue
 8360     55/push-ebp
 8361     89/<- %ebp 4/r32/esp
 8362     # (eax..ecx) = "`a"
 8363     b8/copy-to-eax "`a"/imm32
 8364     8b/-> *eax 1/r32/ecx
 8365     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8366     05/add-to-eax 4/imm32
 8367     # var slice/ecx: slice = {eax, ecx}
 8368     51/push-ecx
 8369     50/push-eax
 8370     89/<- %ecx 4/r32/esp
 8371     #
 8372     (is-identifier? %ecx)
 8373     (check-ints-equal %eax 0 "F - test-is-identifier-backtick")
 8374     # . epilogue
 8375     89/<- %esp 5/r32/ebp
 8376     5d/pop-to-ebp
 8377     c3/return
 8378 
 8379 test-is-identifier-curly-brace-open:
 8380     # character after 'z' is invalid; also used for blocks
 8381     # . prologue
 8382     55/push-ebp
 8383     89/<- %ebp 4/r32/esp
 8384     # (eax..ecx) = "{a"
 8385     b8/copy-to-eax "{a"/imm32
 8386     8b/-> *eax 1/r32/ecx
 8387     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8388     05/add-to-eax 4/imm32
 8389     # var slice/ecx: slice = {eax, ecx}
 8390     51/push-ecx
 8391     50/push-eax
 8392     89/<- %ecx 4/r32/esp
 8393     #
 8394     (is-identifier? %ecx)
 8395     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open")
 8396     # . epilogue
 8397     89/<- %esp 5/r32/ebp
 8398     5d/pop-to-ebp
 8399     c3/return
 8400 
 8401 test-is-identifier-curly-brace-close:
 8402     # . prologue
 8403     55/push-ebp
 8404     89/<- %ebp 4/r32/esp
 8405     # (eax..ecx) = "}a"
 8406     b8/copy-to-eax "}a"/imm32
 8407     8b/-> *eax 1/r32/ecx
 8408     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8409     05/add-to-eax 4/imm32
 8410     # var slice/ecx: slice = {eax, ecx}
 8411     51/push-ecx
 8412     50/push-eax
 8413     89/<- %ecx 4/r32/esp
 8414     #
 8415     (is-identifier? %ecx)
 8416     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close")
 8417     # . epilogue
 8418     89/<- %esp 5/r32/ebp
 8419     5d/pop-to-ebp
 8420     c3/return
 8421 
 8422 test-is-identifier-hyphen:
 8423     # disallow leading '-' since '->' has special meaning
 8424     # . prologue
 8425     55/push-ebp
 8426     89/<- %ebp 4/r32/esp
 8427     # (eax..ecx) = "-a"
 8428     b8/copy-to-eax "-a"/imm32
 8429     8b/-> *eax 1/r32/ecx
 8430     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8431     05/add-to-eax 4/imm32
 8432     # var slice/ecx: slice = {eax, ecx}
 8433     51/push-ecx
 8434     50/push-eax
 8435     89/<- %ecx 4/r32/esp
 8436     #
 8437     (is-identifier? %ecx)
 8438     (check-ints-equal %eax 0 "F - test-is-identifier-hyphen")
 8439     # . epilogue
 8440     89/<- %esp 5/r32/ebp
 8441     5d/pop-to-ebp
 8442     c3/return
 8443 
 8444 populate-mu-function-body:  # in: (addr buffered-file), out: (addr function), vars: (addr stack live-var), err: (addr buffered-file), ed: (addr exit-descriptor)
 8445     # . prologue
 8446     55/push-ebp
 8447     89/<- %ebp 4/r32/esp
 8448     # . save registers
 8449     50/push-eax
 8450     56/push-esi
 8451     57/push-edi
 8452     # esi = in
 8453     8b/-> *(ebp+8) 6/r32/esi
 8454     # edi = out
 8455     8b/-> *(ebp+0xc) 7/r32/edi
 8456     # initialize some global state
 8457     c7 0/subop/copy *Curr-block-depth 1/imm32
 8458     # parse-mu-block(in, vars, out, out->body)
 8459     8d/copy-address *(edi+0x18) 0/r32/eax  # Function-body
 8460     (parse-mu-block %esi *(ebp+0x10) %edi %eax *(ebp+0x14) *(ebp+0x18))
 8461 $populate-mu-function-body:end:
 8462     # . restore registers
 8463     5f/pop-to-edi
 8464     5e/pop-to-esi
 8465     58/pop-to-eax
 8466     # . epilogue
 8467     89/<- %esp 5/r32/ebp
 8468     5d/pop-to-ebp
 8469     c3/return
 8470 
 8471 # parses a block, assuming that the leading '{' has already been read by the caller
 8472 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)
 8473     # pseudocode:
 8474     #   var line: (stream byte 512)
 8475     #   var word-slice: slice
 8476     #   allocate(Heap, Stmt-size, out)
 8477     #   var out-addr: (addr block) = lookup(*out)
 8478     #   out-addr->tag = 0/block
 8479     #   out-addr->var = some unique name
 8480     #   push(vars, {out-addr->var, false})
 8481     #   while true                                  # line loop
 8482     #     clear-stream(line)
 8483     #     read-line-buffered(in, line)
 8484     #     if (line->write == 0) break               # end of file
 8485     #     word-slice = next-mu-token(line)
 8486     #     if slice-empty?(word-slice)               # end of line
 8487     #       continue
 8488     #     else if slice-starts-with?(word-slice, "#")
 8489     #       continue
 8490     #     else if slice-equal?(word-slice, "{")
 8491     #       assert(no-tokens-in(line))
 8492     #       block = parse-mu-block(in, vars, fn)
 8493     #       append-to-block(out-addr, block)
 8494     #     else if slice-equal?(word-slice, "}")
 8495     #       break
 8496     #     else if slice-ends-with?(word-slice, ":")
 8497     #       # TODO: error-check the rest of 'line'
 8498     #       --word-slice->end to skip ':'
 8499     #       named-block = parse-mu-named-block(word-slice, in, vars, fn)
 8500     #       append-to-block(out-addr, named-block)
 8501     #     else if slice-equal?(word-slice, "var")
 8502     #       var-def = parse-mu-var-def(line, vars, fn)
 8503     #       append-to-block(out-addr, var-def)
 8504     #     else
 8505     #       stmt = parse-mu-stmt(line, vars, fn)
 8506     #       append-to-block(out-addr, stmt)
 8507     #   pop(vars)
 8508     #
 8509     # . prologue
 8510     55/push-ebp
 8511     89/<- %ebp 4/r32/esp
 8512     # . save registers
 8513     50/push-eax
 8514     51/push-ecx
 8515     52/push-edx
 8516     53/push-ebx
 8517     57/push-edi
 8518     # var line/ecx: (stream byte 512)
 8519     81 5/subop/subtract %esp 0x200/imm32
 8520     68/push 0x200/imm32/size
 8521     68/push 0/imm32/read
 8522     68/push 0/imm32/write
 8523     89/<- %ecx 4/r32/esp
 8524     # var word-slice/edx: slice
 8525     68/push 0/imm32/end
 8526     68/push 0/imm32/start
 8527     89/<- %edx 4/r32/esp
 8528     # allocate into out
 8529     (allocate Heap *Stmt-size *(ebp+0x14))
 8530     # var out-addr/edi: (addr block) = lookup(*out)
 8531     8b/-> *(ebp+0x14) 7/r32/edi
 8532     (lookup *edi *(edi+4))  # => eax
 8533     89/<- %edi 0/r32/eax
 8534     # out-addr->tag is 0 (block) by default
 8535     # set out-addr->var
 8536     8d/copy-address *(edi+0xc) 0/r32/eax  # Block-var
 8537     (new-block-name *(ebp+0x10) %eax)
 8538     # push(vars, out-addr->var)
 8539     (push *(ebp+0xc) *(edi+0xc))  # Block-var
 8540     (push *(ebp+0xc) *(edi+0x10))  # Block-var
 8541     (push *(ebp+0xc) 0)  # false
 8542     # increment *Curr-block-depth
 8543     ff 0/subop/increment *Curr-block-depth
 8544     {
 8545 $parse-mu-block:line-loop:
 8546       # line = read-line-buffered(in)
 8547       (clear-stream %ecx)
 8548       (read-line-buffered *(ebp+8) %ecx)
 8549 #?       (write-buffered Stderr "line: ")
 8550 #?       (write-stream-data Stderr %ecx)
 8551 #? #?       (write-buffered Stderr Newline)  # line has its own newline
 8552 #?       (flush Stderr)
 8553 #?       (rewind-stream %ecx)
 8554       # if (line->write == 0) break
 8555       81 7/subop/compare *ecx 0/imm32
 8556       0f 84/jump-if-= break/disp32
 8557 #?       (write-buffered Stderr "vars:\n")
 8558 #?       (dump-vars *(ebp+0xc))
 8559       # word-slice = next-mu-token(line)
 8560       (next-mu-token %ecx %edx)
 8561 #?       (write-buffered Stderr "word: ")
 8562 #?       (write-slice-buffered Stderr %edx)
 8563 #?       (write-buffered Stderr Newline)
 8564 #?       (flush Stderr)
 8565       # if slice-empty?(word-slice) continue
 8566       (slice-empty? %edx)
 8567       3d/compare-eax-and 0/imm32/false
 8568       0f 85/jump-if-!= loop/disp32
 8569       # if (slice-starts-with?(word-slice, '#') continue
 8570       # . eax = *word-slice->start
 8571       8b/-> *edx 0/r32/eax
 8572       8a/copy-byte *eax 0/r32/AL
 8573       81 4/subop/and %eax 0xff/imm32
 8574       # . if (eax == '#') continue
 8575       3d/compare-eax-and 0x23/imm32/hash
 8576       0f 84/jump-if-= loop/disp32
 8577       # if slice-equal?(word-slice, "{")
 8578       {
 8579 $parse-mu-block:check-for-block:
 8580         (slice-equal? %edx "{")
 8581         3d/compare-eax-and 0/imm32/false
 8582         74/jump-if-= break/disp8
 8583         (check-no-tokens-left %ecx)
 8584         # parse new block and append
 8585         # . var tmp/eax: (handle block)
 8586         68/push 0/imm32
 8587         68/push 0/imm32
 8588         89/<- %eax 4/r32/esp
 8589         # .
 8590         (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 8591         (append-to-block Heap %edi  *eax *(eax+4))
 8592         # . reclaim tmp
 8593         81 0/subop/add %esp 8/imm32
 8594         # .
 8595         e9/jump $parse-mu-block:line-loop/disp32
 8596       }
 8597       # if slice-equal?(word-slice, "}") break
 8598 $parse-mu-block:check-for-end:
 8599       (slice-equal? %edx "}")
 8600       3d/compare-eax-and 0/imm32/false
 8601       0f 85/jump-if-!= break/disp32
 8602       # if slice-ends-with?(word-slice, ":") parse named block and append
 8603       {
 8604 $parse-mu-block:check-for-named-block:
 8605         # . eax = *(word-slice->end-1)
 8606         8b/-> *(edx+4) 0/r32/eax
 8607         48/decrement-eax
 8608         8a/copy-byte *eax 0/r32/AL
 8609         81 4/subop/and %eax 0xff/imm32
 8610         # . if (eax != ':') break
 8611         3d/compare-eax-and 0x3a/imm32/colon
 8612         0f 85/jump-if-!= break/disp32
 8613         # TODO: error-check the rest of 'line'
 8614         #
 8615         # skip ':'
 8616         ff 1/subop/decrement *(edx+4)  # Slice-end
 8617         # var tmp/eax: (handle block)
 8618         68/push 0/imm32
 8619         68/push 0/imm32
 8620         89/<- %eax 4/r32/esp
 8621         #
 8622         (parse-mu-named-block %edx *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 8623         (append-to-block Heap %edi  *eax *(eax+4))
 8624         # reclaim tmp
 8625         81 0/subop/add %esp 8/imm32
 8626         #
 8627         e9/jump $parse-mu-block:line-loop/disp32
 8628       }
 8629       # if slice-equal?(word-slice, "var")
 8630       {
 8631 $parse-mu-block:check-for-var:
 8632         (slice-equal? %edx "var")
 8633         3d/compare-eax-and 0/imm32/false
 8634         74/jump-if-= break/disp8
 8635         # var tmp/eax: (handle block)
 8636         68/push 0/imm32
 8637         68/push 0/imm32
 8638         89/<- %eax 4/r32/esp
 8639         #
 8640         (parse-mu-var-def %ecx *(ebp+0xc) %eax *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
 8641         (append-to-block Heap %edi  *eax *(eax+4))
 8642         # reclaim tmp
 8643         81 0/subop/add %esp 8/imm32
 8644         #
 8645         e9/jump $parse-mu-block:line-loop/disp32
 8646       }
 8647 $parse-mu-block:regular-stmt:
 8648       # otherwise
 8649       # var tmp/eax: (handle block)
 8650       68/push 0/imm32
 8651       68/push 0/imm32
 8652       89/<- %eax 4/r32/esp
 8653       #
 8654       (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 8655       (append-to-block Heap %edi  *eax *(eax+4))
 8656       # reclaim tmp
 8657       81 0/subop/add %esp 8/imm32
 8658       #
 8659       e9/jump loop/disp32
 8660     } # end line loop
 8661     (clean-up-blocks *(ebp+0xc) *Curr-block-depth *(ebp+0x10))
 8662     # decrement *Curr-block-depth
 8663     ff 1/subop/decrement *Curr-block-depth
 8664     # pop(vars)
 8665     (pop *(ebp+0xc))  # => eax
 8666     (pop *(ebp+0xc))  # => eax
 8667     (pop *(ebp+0xc))  # => eax
 8668 $parse-mu-block:end:
 8669     # . reclaim locals
 8670     81 0/subop/add %esp 0x214/imm32
 8671     # . restore registers
 8672     5f/pop-to-edi
 8673     5b/pop-to-ebx
 8674     5a/pop-to-edx
 8675     59/pop-to-ecx
 8676     58/pop-to-eax
 8677     # . epilogue
 8678     89/<- %esp 5/r32/ebp
 8679     5d/pop-to-ebp
 8680     c3/return
 8681 
 8682 $parse-mu-block:abort:
 8683     # error("'{' or '}' should be on its own line, but got '")
 8684     (write-buffered *(ebp+0x18) "'{' or '}' should be on its own line, but got '")
 8685     (rewind-stream %ecx)
 8686     (write-stream-data *(ebp+0x18) %ecx)
 8687     (write-buffered *(ebp+0x18) "'\n")
 8688     (flush *(ebp+0x18))
 8689     (stop *(ebp+0x1c) 1)
 8690     # never gets here
 8691 
 8692 new-block-name:  # fn: (addr function), out: (addr handle var)
 8693     # . prologue
 8694     55/push-ebp
 8695     89/<- %ebp 4/r32/esp
 8696     # . save registers
 8697     50/push-eax
 8698     51/push-ecx
 8699     52/push-edx
 8700     # var n/ecx: int = len(fn->name) + 10 for an int + 2 for '$:'
 8701     8b/-> *(ebp+8) 0/r32/eax
 8702     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 8703     8b/-> *eax 0/r32/eax  # String-size
 8704     05/add-to-eax 0xd/imm32  # 10 + 2 for '$:'
 8705     89/<- %ecx 0/r32/eax
 8706     # var name/edx: (stream byte n)
 8707     29/subtract-from %esp 1/r32/ecx
 8708     ff 6/subop/push %ecx
 8709     68/push 0/imm32/read
 8710     68/push 0/imm32/write
 8711     89/<- %edx 4/r32/esp
 8712     (clear-stream %edx)
 8713     # eax = fn->name
 8714     8b/-> *(ebp+8) 0/r32/eax
 8715     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 8716     # construct result using Next-block-index (and increment it)
 8717     (write %edx "$")
 8718     (write %edx %eax)
 8719     (write %edx ":")
 8720     (write-int32-hex %edx *Next-block-index)
 8721     ff 0/subop/increment *Next-block-index
 8722     # var s/eax: slice = {name->data, name->data + name->write}  (clobbering edx)
 8723     # . eax = name->write
 8724     8b/-> *edx 0/r32/eax
 8725     # . edx = name->data
 8726     8d/copy-address *(edx+0xc) 2/r32/edx
 8727     # . eax = name->write + name->data
 8728     01/add-to %eax 2/r32/edx
 8729     # . push {edx, eax}
 8730     ff 6/subop/push %eax
 8731     ff 6/subop/push %edx
 8732     89/<- %eax 4/r32/esp
 8733     # out = new literal(s)
 8734     (new-literal Heap %eax *(ebp+0xc))
 8735 #?     8b/-> *(ebp+0xc) 0/r32/eax
 8736 #?     (write-buffered Stderr "type allocid in caller after new-literal: ")
 8737 #?     (write-int32-hex-buffered Stderr *(eax+8))
 8738 #?     (write-buffered Stderr " for var ")
 8739 #?     (write-int32-hex-buffered Stderr %eax)
 8740 #?     (write-buffered Stderr Newline)
 8741 #?     (flush Stderr)
 8742 $new-block-name:end:
 8743     # . reclaim locals
 8744     81 0/subop/add %ecx 0xc/imm32  # name.{read/write/len}
 8745     81 0/subop/add %ecx 8/imm32  # slice
 8746     01/add-to %esp 1/r32/ecx
 8747     # . restore registers
 8748     5a/pop-to-edx
 8749     59/pop-to-ecx
 8750     58/pop-to-eax
 8751     # . epilogue
 8752     89/<- %esp 5/r32/ebp
 8753     5d/pop-to-ebp
 8754     c3/return
 8755 
 8756 check-no-tokens-left:  # line: (addr stream byte)
 8757     # . prologue
 8758     55/push-ebp
 8759     89/<- %ebp 4/r32/esp
 8760     # . save registers
 8761     50/push-eax
 8762     51/push-ecx
 8763     # var s/ecx: slice
 8764     68/push 0/imm32/end
 8765     68/push 0/imm32/start
 8766     89/<- %ecx 4/r32/esp
 8767     #
 8768     (next-mu-token *(ebp+8) %ecx)
 8769     # if slice-empty?(s) return
 8770     (slice-empty? %ecx)
 8771     3d/compare-eax-and 0/imm32/false
 8772     75/jump-if-!= $check-no-tokens-left:end/disp8
 8773     # if (slice-starts-with?(s, '#') return
 8774     # . eax = *s->start
 8775     8b/-> *edx 0/r32/eax
 8776     8a/copy-byte *eax 0/r32/AL
 8777     81 4/subop/and %eax 0xff/imm32
 8778     # . if (eax == '#') continue
 8779     3d/compare-eax-and 0x23/imm32/hash
 8780     74/jump-if-= $check-no-tokens-left:end/disp8
 8781     # abort
 8782     (write-buffered Stderr "'{' or '}' should be on its own line, but got '")
 8783     (rewind-stream %ecx)
 8784     (write-stream 2 %ecx)
 8785     (write-buffered Stderr "'\n")
 8786     (flush Stderr)
 8787     # . syscall(exit, 1)
 8788     bb/copy-to-ebx  1/imm32
 8789     e8/call syscall_exit/disp32
 8790     # never gets here
 8791 $check-no-tokens-left:end:
 8792     # . reclaim locals
 8793     81 0/subop/add %esp 8/imm32
 8794     # . restore registers
 8795     59/pop-to-ecx
 8796     58/pop-to-eax
 8797     # . epilogue
 8798     89/<- %esp 5/r32/ebp
 8799     5d/pop-to-ebp
 8800     c3/return
 8801 
 8802 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)
 8803     # pseudocode:
 8804     #   var v: (handle var)
 8805     #   new-literal(name, v)
 8806     #   push(vars, {v, false})
 8807     #   parse-mu-block(in, vars, fn, out)
 8808     #   pop(vars)
 8809     #   out->tag = block
 8810     #   out->var = v
 8811     #
 8812     # . prologue
 8813     55/push-ebp
 8814     89/<- %ebp 4/r32/esp
 8815     # . save registers
 8816     50/push-eax
 8817     51/push-ecx
 8818     57/push-edi
 8819     # var v/ecx: (handle var)
 8820     68/push 0/imm32
 8821     68/push 0/imm32
 8822     89/<- %ecx 4/r32/esp
 8823     #
 8824     (new-literal Heap *(ebp+8) %ecx)
 8825     # push(vars, v)
 8826     (push *(ebp+0x10) *ecx)
 8827     (push *(ebp+0x10) *(ecx+4))
 8828     (push *(ebp+0x10) 0)  # false
 8829     #
 8830     (parse-mu-block *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20))
 8831     # pop v off vars
 8832     (pop *(ebp+0x10))  # => eax
 8833     (pop *(ebp+0x10))  # => eax
 8834     (pop *(ebp+0x10))  # => eax
 8835     # var out-addr/edi: (addr stmt) = lookup(*out)
 8836     8b/-> *(ebp+0x18) 7/r32/edi
 8837     (lookup *edi *(edi+4))  # => eax
 8838     89/<- %edi 0/r32/eax
 8839     # out-addr->tag = named-block
 8840     c7 0/subop/copy *edi 0/imm32/block  # Stmt-tag
 8841     # out-addr->var = v
 8842     8b/-> *ecx 0/r32/eax
 8843     89/<- *(edi+0xc) 0/r32/eax  # Block-var
 8844     8b/-> *(ecx+4) 0/r32/eax
 8845     89/<- *(edi+0x10) 0/r32/eax  # Block-var
 8846 $parse-mu-named-block:end:
 8847     # . reclaim locals
 8848     81 0/subop/add %esp 8/imm32
 8849     # . restore registers
 8850     5f/pop-to-edi
 8851     59/pop-to-ecx
 8852     58/pop-to-eax
 8853     # . epilogue
 8854     89/<- %esp 5/r32/ebp
 8855     5d/pop-to-ebp
 8856     c3/return
 8857 
 8858 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)
 8859     # . prologue
 8860     55/push-ebp
 8861     89/<- %ebp 4/r32/esp
 8862     # . save registers
 8863     50/push-eax
 8864     51/push-ecx
 8865     52/push-edx
 8866     53/push-ebx
 8867     57/push-edi
 8868     # edi = out
 8869     8b/-> *(ebp+0x10) 7/r32/edi
 8870     # var word-slice/ecx: slice
 8871     68/push 0/imm32/end
 8872     68/push 0/imm32/start
 8873     89/<- %ecx 4/r32/esp
 8874     # var v/edx: (handle var)
 8875     68/push 0/imm32
 8876     68/push 0/imm32
 8877     89/<- %edx 4/r32/esp
 8878     # v = parse-var-with-type(next-mu-token(line))
 8879     (next-mu-token *(ebp+8) %ecx)
 8880     (parse-var-with-type %ecx *(ebp+8) %edx *(ebp+0x18) *(ebp+0x1c))
 8881     # var v-addr/eax: (addr var)
 8882     (lookup *edx *(edx+4))  # => eax
 8883     # v->block-depth = *Curr-block-depth
 8884     8b/-> *Curr-block-depth 3/r32/ebx
 8885     89/<- *(eax+0x10) 3/r32/ebx  # Var-block-depth
 8886     # either v has no register and there's no more to this line
 8887     8b/-> *(eax+0x18) 0/r32/eax  # Var-register
 8888     3d/compare-eax-and 0/imm32
 8889     {
 8890       75/jump-if-!= break/disp8
 8891       # TODO: disallow vars of type 'byte' on the stack
 8892       # ensure that there's nothing else on this line
 8893       (next-mu-token *(ebp+8) %ecx)
 8894       (slice-empty? %ecx)  # => eax
 8895       3d/compare-eax-and 0/imm32/false
 8896       0f 84/jump-if-= $parse-mu-var-def:error2/disp32
 8897       #
 8898       (new-var-def Heap  *edx *(edx+4)  %edi)
 8899       e9/jump $parse-mu-var-def:update-vars/disp32
 8900     }
 8901     # or v has a register and there's more to this line
 8902     {
 8903       0f 84/jump-if-= break/disp32
 8904       # TODO: disallow vars of type 'byte' in registers 'esi' or 'edi'
 8905       # TODO: vars of type 'byte' should only be initialized by clearing to 0
 8906       # ensure that the next word is '<-'
 8907       (next-mu-token *(ebp+8) %ecx)
 8908       (slice-equal? %ecx "<-")  # => eax
 8909       3d/compare-eax-and 0/imm32/false
 8910       0f 84/jump-if-= $parse-mu-var-def:error1/disp32
 8911       #
 8912       (new-reg-var-def Heap  *edx *(edx+4)  %edi)
 8913       (lookup *edi *(edi+4))  # => eax
 8914       (add-operation-and-inputs-to-stmt %eax *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 8915     }
 8916 $parse-mu-var-def:update-vars:
 8917     # push 'v' at end of function
 8918     (push *(ebp+0xc) *edx)
 8919     (push *(ebp+0xc) *(edx+4))
 8920     (push *(ebp+0xc) 0)  # Live-var-register-spilled is unused during parsing
 8921 $parse-mu-var-def:end:
 8922     # . reclaim locals
 8923     81 0/subop/add %esp 0x10/imm32
 8924     # . restore registers
 8925     5f/pop-to-edi
 8926     5b/pop-to-ebx
 8927     5a/pop-to-edx
 8928     59/pop-to-ecx
 8929     58/pop-to-eax
 8930     # . epilogue
 8931     89/<- %esp 5/r32/ebp
 8932     5d/pop-to-ebp
 8933     c3/return
 8934 
 8935 $parse-mu-var-def:error1:
 8936     (rewind-stream *(ebp+8))
 8937     # error("register variable requires a valid instruction to initialize but got '" line "'\n")
 8938     (write-buffered *(ebp+0x18) "register variable requires a valid instruction to initialize but got '")
 8939     (flush *(ebp+0x18))
 8940     (write-stream-data *(ebp+0x18) *(ebp+8))
 8941     (write-buffered *(ebp+0x18) "'\n")
 8942     (flush *(ebp+0x18))
 8943     (stop *(ebp+0x1c) 1)
 8944     # never gets here
 8945 
 8946 $parse-mu-var-def:error2:
 8947     (rewind-stream *(ebp+8))
 8948     # error("fn " fn ": var " var ": variables on the stack can't take an initializer\n")
 8949     (write-buffered *(ebp+0x18) "fn ")
 8950     8b/-> *(ebp+0x14) 0/r32/eax
 8951     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 8952     (write-buffered *(ebp+0x18) %eax)
 8953     (write-buffered *(ebp+0x18) ": var ")
 8954     # var v-addr/eax: (addr var) = lookup(v)
 8955     (lookup *edx *(edx+4))  # => eax
 8956     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 8957     (write-buffered *(ebp+0x18) %eax)
 8958     (write-buffered *(ebp+0x18) ": variables on the stack can't take an initializer\n")
 8959     (flush *(ebp+0x18))
 8960     (stop *(ebp+0x1c) 1)
 8961     # never gets here
 8962 
 8963 test-parse-mu-var-def:
 8964     # 'var n: int'
 8965     # . prologue
 8966     55/push-ebp
 8967     89/<- %ebp 4/r32/esp
 8968     # setup
 8969     (clear-stream _test-input-stream)
 8970     (write _test-input-stream "n: int\n")  # caller has consumed the 'var'
 8971     c7 0/subop/copy *Curr-block-depth 1/imm32
 8972     # var out/esi: (handle stmt)
 8973     68/push 0/imm32
 8974     68/push 0/imm32
 8975     89/<- %esi 4/r32/esp
 8976     # var vars/ecx: (stack (addr var) 16)
 8977     81 5/subop/subtract %esp 0xc0/imm32
 8978     68/push 0xc0/imm32/size
 8979     68/push 0/imm32/top
 8980     89/<- %ecx 4/r32/esp
 8981     (clear-stack %ecx)
 8982     # convert
 8983     (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0)
 8984     # var out-addr/esi: (addr stmt)
 8985     (lookup *esi *(esi+4))  # => eax
 8986     89/<- %esi 0/r32/eax
 8987     #
 8988     (check-ints-equal *esi 2 "F - test-parse-mu-var-def/tag")  # Stmt-tag is var-def
 8989     # var v/ecx: (addr var) = lookup(out->var)
 8990     (lookup *(esi+4) *(esi+8))  # Vardef-var Vardef-var => eax
 8991     89/<- %ecx 0/r32/eax
 8992     # v->name
 8993     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 8994     (check-strings-equal %eax "n" "F - test-parse-mu-var-def/var-name")
 8995     # v->register
 8996     (check-ints-equal *(ecx+0x18) 0 "F - test-parse-mu-var-def/var-register")  # Var-register
 8997     # v->block-depth
 8998     (check-ints-equal *(ecx+0x10) 1 "F - test-parse-mu-var-def/output-block-depth")  # Var-block-depth
 8999     # v->type == int
 9000     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 9001     (check-ints-equal *eax 1 "F - test-parse-mu-var-def/var-type:0")  # Type-tree-is-atom
 9002     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-var-def/var-type:1")  # Type-tree-value
 9003     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-var-def/var-type:2")  # Type-tree-right
 9004     # . epilogue
 9005     89/<- %esp 5/r32/ebp
 9006     5d/pop-to-ebp
 9007     c3/return
 9008 
 9009 test-parse-mu-reg-var-def:
 9010     # 'var n/eax: int <- copy 0'
 9011     # . prologue
 9012     55/push-ebp
 9013     89/<- %ebp 4/r32/esp
 9014     # setup
 9015     (clear-stream _test-input-stream)
 9016     (write _test-input-stream "n/eax: int <- copy 0\n")  # caller has consumed the 'var'
 9017     c7 0/subop/copy *Curr-block-depth 1/imm32
 9018     # var out/esi: (handle stmt)
 9019     68/push 0/imm32
 9020     68/push 0/imm32
 9021     89/<- %esi 4/r32/esp
 9022     # var vars/ecx: (stack (addr var) 16)
 9023     81 5/subop/subtract %esp 0xc0/imm32
 9024     68/push 0xc0/imm32/size
 9025     68/push 0/imm32/top
 9026     89/<- %ecx 4/r32/esp
 9027     (clear-stack %ecx)
 9028     # convert
 9029     (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0)
 9030     # var out-addr/esi: (addr stmt)
 9031     (lookup *esi *(esi+4))  # => eax
 9032     89/<- %esi 0/r32/eax
 9033     #
 9034     (check-ints-equal *esi 3 "F - test-parse-mu-reg-var-def/tag")  # Stmt-tag is reg-var-def
 9035     # var v/ecx: (addr var) = lookup(out->outputs->value)
 9036     # . eax: (addr stmt-var) = lookup(out->outputs)
 9037     (lookup *(esi+0x14) *(esi+0x18))  # Regvardef-outputs Regvardef-outputs => eax
 9038     # .
 9039     (check-ints-equal *(eax+8) 0 "F - test-parse-mu-reg-var-def/single-output")  # Stmt-var-next
 9040     # . eax: (addr var) = lookup(eax->value)
 9041     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9042     # . ecx = eax
 9043     89/<- %ecx 0/r32/eax
 9044     # v->name
 9045     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 9046     (check-strings-equal %eax "n" "F - test-parse-mu-reg-var-def/output-name")  # Var-name
 9047     # v->register
 9048     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 9049     (check-strings-equal %eax "eax" "F - test-parse-mu-reg-var-def/output-register")
 9050     # v->block-depth
 9051     (check-ints-equal *(ecx+0x10) 1 "F - test-parse-mu-reg-var-def/output-block-depth")  # Var-block-depth
 9052     # v->type == int
 9053     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 9054     (check-ints-equal *eax 1 "F - test-parse-mu-reg-var-def/output-type:0")  # Type-tree-is-atom
 9055     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-reg-var-def/output-type:1")  # Type-tree-value
 9056     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-reg-var-def/output-type:2")  # Type-tree-right
 9057     # . epilogue
 9058     89/<- %esp 5/r32/ebp
 9059     5d/pop-to-ebp
 9060     c3/return
 9061 
 9062 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)
 9063     # Carefully push any outputs on the vars stack _after_ reading the inputs
 9064     # that may conflict with them.
 9065     #
 9066     # The only situation in which outputs are pushed here (when it's not a
 9067     # 'var' vardef stmt), and so can possibly conflict with inputs, is if the
 9068     # output is a function output.
 9069     #
 9070     # pseudocode:
 9071     #   var name: slice
 9072     #   allocate(Heap, Stmt-size, out)
 9073     #   var out-addr: (addr stmt) = lookup(*out)
 9074     #   out-addr->tag = stmt
 9075     #   if stmt-has-outputs?(line)
 9076     #     while true
 9077     #       name = next-mu-token(line)
 9078     #       if (name == '<-') break
 9079     #       assert(is-identifier?(name))
 9080     #       var v: (handle var) = lookup-var-or-find-in-fn-outputs(name, vars, fn)
 9081     #       out-addr->outputs = append(v, out-addr->outputs)
 9082     #   add-operation-and-inputs-to-stmt(out-addr, line, vars)
 9083     #   for output in stmt->outputs:
 9084     #     maybe-define-var(output, vars)
 9085     #
 9086     # . prologue
 9087     55/push-ebp
 9088     89/<- %ebp 4/r32/esp
 9089     # . save registers
 9090     50/push-eax
 9091     51/push-ecx
 9092     52/push-edx
 9093     53/push-ebx
 9094     57/push-edi
 9095     # var name/ecx: slice
 9096     68/push 0/imm32/end
 9097     68/push 0/imm32/start
 9098     89/<- %ecx 4/r32/esp
 9099     # var is-deref?/edx: boolean = false
 9100     ba/copy-to-edx 0/imm32/false
 9101     # var v: (handle var)
 9102     68/push 0/imm32
 9103     68/push 0/imm32
 9104     89/<- %ebx 4/r32/esp
 9105     #
 9106     (allocate Heap *Stmt-size *(ebp+0x14))
 9107     # var out-addr/edi: (addr stmt) = lookup(*out)
 9108     8b/-> *(ebp+0x14) 7/r32/edi
 9109     (lookup *edi *(edi+4))  # => eax
 9110     89/<- %edi 0/r32/eax
 9111     # out-addr->tag = 1/stmt
 9112     c7 0/subop/copy *edi 1/imm32/stmt1  # Stmt-tag
 9113     {
 9114       (stmt-has-outputs? *(ebp+8))
 9115       3d/compare-eax-and 0/imm32/false
 9116       0f 84/jump-if-= break/disp32
 9117       {
 9118 $parse-mu-stmt:read-outputs:
 9119         # name = next-mu-token(line)
 9120         (next-mu-token *(ebp+8) %ecx)
 9121         # if slice-empty?(word-slice) break
 9122         (slice-empty? %ecx)  # => eax
 9123         3d/compare-eax-and 0/imm32/false
 9124         0f 85/jump-if-!= break/disp32
 9125         # if (name == "<-") break
 9126         (slice-equal? %ecx "<-")  # => eax
 9127         3d/compare-eax-and 0/imm32/false
 9128         0f 85/jump-if-!= break/disp32
 9129         # is-deref? = false
 9130         ba/copy-to-edx 0/imm32/false
 9131         # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
 9132         8b/-> *ecx 0/r32/eax  # Slice-start
 9133         8a/copy-byte *eax 0/r32/AL
 9134         81 4/subop/and %eax 0xff/imm32
 9135         3d/compare-eax-and 0x2a/imm32/asterisk
 9136         {
 9137           75/jump-if-!= break/disp8
 9138           ff 0/subop/increment *ecx
 9139           ba/copy-to-edx 1/imm32/true
 9140         }
 9141         # assert(is-identifier?(name))
 9142         (is-identifier? %ecx)  # => eax
 9143         3d/compare-eax-and 0/imm32/false
 9144         0f 84/jump-if-= $parse-mu-stmt:abort/disp32
 9145         #
 9146         (lookup-var-or-find-in-fn-outputs %ecx *(ebp+0xc) *(ebp+0x10) %ebx *(ebp+0x18) *(ebp+0x1c))
 9147         8d/copy-address *(edi+0x14) 0/r32/eax  # Stmt1-outputs
 9148         (append-stmt-var Heap  *ebx *(ebx+4)  *(edi+0x14) *(edi+0x18)  %edx  %eax)  # Stmt1-outputs
 9149         #
 9150         e9/jump loop/disp32
 9151       }
 9152     }
 9153     (add-operation-and-inputs-to-stmt %edi *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
 9154 $parse-mu-stmt:define-outputs:
 9155     # var output/edi: (addr stmt-var) = lookup(out-addr->outputs)
 9156     (lookup *(edi+0x14) *(edi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
 9157     89/<- %edi 0/r32/eax
 9158     {
 9159 $parse-mu-stmt:define-outputs-loop:
 9160       # if (output == null) break
 9161       81 7/subop/compare %edi 0/imm32
 9162       74/jump-if-= break/disp8
 9163       #
 9164       (maybe-define-var *edi *(edi+4)  *(ebp+0xc))  # if output is a deref, then it's already been defined,
 9165                                                     # and must be in vars. This call will be a no-op, but safe.
 9166       # output = output->next
 9167       (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
 9168       89/<- %edi 0/r32/eax
 9169       #
 9170       eb/jump loop/disp8
 9171     }
 9172 $parse-mu-stmt:end:
 9173     # . reclaim locals
 9174     81 0/subop/add %esp 0x10/imm32
 9175     # . restore registers
 9176     5f/pop-to-edi
 9177     5b/pop-to-ebx
 9178     5a/pop-to-edx
 9179     59/pop-to-ecx
 9180     58/pop-to-eax
 9181     # . epilogue
 9182     89/<- %esp 5/r32/ebp
 9183     5d/pop-to-ebp
 9184     c3/return
 9185 
 9186 $parse-mu-stmt:abort:
 9187     # error("invalid identifier '" name "'\n")
 9188     (write-buffered *(ebp+0x18) "invalid identifier '")
 9189     (write-slice-buffered *(ebp+0x18) %ecx)
 9190     (write-buffered *(ebp+0x18) "'\n")
 9191     (flush *(ebp+0x18))
 9192     (stop *(ebp+0x1c) 1)
 9193     # never gets here
 9194 
 9195 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)
 9196     # pseudocode:
 9197     #   stmt->name = slice-to-string(next-mu-token(line))
 9198     #   while true
 9199     #     name = next-mu-token(line)
 9200     #     v = lookup-var-or-literal(name)
 9201     #     stmt->inouts = append(v, stmt->inouts)
 9202     #
 9203     # . prologue
 9204     55/push-ebp
 9205     89/<- %ebp 4/r32/esp
 9206     # . save registers
 9207     50/push-eax
 9208     51/push-ecx
 9209     52/push-edx
 9210     53/push-ebx
 9211     56/push-esi
 9212     57/push-edi
 9213     # edi = stmt
 9214     8b/-> *(ebp+8) 7/r32/edi
 9215     # var name/ecx: slice
 9216     68/push 0/imm32/end
 9217     68/push 0/imm32/start
 9218     89/<- %ecx 4/r32/esp
 9219     # var is-deref?/edx: boolean = false
 9220     ba/copy-to-edx 0/imm32/false
 9221     # var v/esi: (handle var)
 9222     68/push 0/imm32
 9223     68/push 0/imm32
 9224     89/<- %esi 4/r32/esp
 9225 $add-operation-and-inputs-to-stmt:read-operation:
 9226     (next-mu-token *(ebp+0xc) %ecx)
 9227     8d/copy-address *(edi+4) 0/r32/eax  # Stmt1-operation or Regvardef-operationStmt1-operation or Regvardef-operation
 9228     (slice-to-string Heap %ecx %eax)
 9229     # var is-get?/ebx: boolean = (name == "get")
 9230     (slice-equal? %ecx "get")  # => eax
 9231     89/<- %ebx 0/r32/eax
 9232     {
 9233 $add-operation-and-inputs-to-stmt:read-inouts:
 9234       # name = next-mu-token(line)
 9235       (next-mu-token *(ebp+0xc) %ecx)
 9236       # if slice-empty?(word-slice) break
 9237       (slice-empty? %ecx)  # => eax
 9238       3d/compare-eax-and 0/imm32/false
 9239       0f 85/jump-if-!= break/disp32
 9240       # if (name == "<-") abort
 9241       (slice-equal? %ecx "<-")
 9242       3d/compare-eax-and 0/imm32/false
 9243       0f 85/jump-if-!= $add-operation-and-inputs-to-stmt:abort/disp32
 9244       # if (is-get? && second operand) lookup or create offset
 9245       {
 9246         81 7/subop/compare %ebx 0/imm32/false
 9247         74/jump-if-= break/disp8
 9248         (lookup *(edi+0xc) *(edi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9249         3d/compare-eax-and 0/imm32
 9250         74/jump-if-= break/disp8
 9251         (lookup-or-create-constant %eax %ecx %esi)
 9252 #?         (lookup *esi *(esi+4))
 9253 #?         (write-buffered Stderr "creating new output var ")
 9254 #?         (write-int32-hex-buffered Stderr %eax)
 9255 #?         (write-buffered Stderr " for field called ")
 9256 #?         (write-slice-buffered Stderr %ecx)
 9257 #?         (write-buffered Stderr "; var name ")
 9258 #?         (lookup *eax *(eax+4))  # Var-name
 9259 #?         (write-buffered Stderr %eax)
 9260 #?         (write-buffered Stderr Newline)
 9261 #?         (flush Stderr)
 9262         e9/jump $add-operation-and-inputs-to-stmt:save-var/disp32
 9263       }
 9264       # is-deref? = false
 9265       ba/copy-to-edx 0/imm32/false
 9266       # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
 9267       8b/-> *ecx 0/r32/eax  # Slice-start
 9268       8a/copy-byte *eax 0/r32/AL
 9269       81 4/subop/and %eax 0xff/imm32
 9270       3d/compare-eax-and 0x2a/imm32/asterisk
 9271       {
 9272         75/jump-if-!= break/disp8
 9273 $add-operation-and-inputs-to-stmt:inout-is-deref:
 9274         ff 0/subop/increment *ecx
 9275         ba/copy-to-edx 1/imm32/true
 9276       }
 9277       (lookup-var-or-literal %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 9278 $add-operation-and-inputs-to-stmt:save-var:
 9279       8d/copy-address *(edi+0xc) 0/r32/eax
 9280       (append-stmt-var Heap  *esi *(esi+4)  *(edi+0xc) *(edi+0x10)  %edx  %eax)  # Stmt1-inouts or Regvardef-inouts
 9281       #
 9282       e9/jump loop/disp32
 9283     }
 9284 $add-operation-and-inputs-to-stmt:end:
 9285     # . reclaim locals
 9286     81 0/subop/add %esp 0x10/imm32
 9287     # . restore registers
 9288     5f/pop-to-edi
 9289     5e/pop-to-esi
 9290     5b/pop-to-ebx
 9291     5a/pop-to-edx
 9292     59/pop-to-ecx
 9293     58/pop-to-eax
 9294     # . epilogue
 9295     89/<- %esp 5/r32/ebp
 9296     5d/pop-to-ebp
 9297     c3/return
 9298 
 9299 $add-operation-and-inputs-to-stmt:abort:
 9300     # error("fn ___: invalid identifier in '" line "'\n")
 9301     (write-buffered *(ebp+0x18) "fn ")
 9302     8b/-> *(ebp+0x14) 0/r32/eax
 9303     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9304     (write-buffered *(ebp+0x18) %eax)
 9305     (rewind-stream *(ebp+0xc))
 9306     (write-buffered *(ebp+0x18) ": invalid identifier in '")
 9307     (write-stream-data *(ebp+0x18) *(ebp+0xc))
 9308     (write-buffered *(ebp+0x18) "'\n")
 9309     (flush *(ebp+0x18))
 9310     (stop *(ebp+0x1c) 1)
 9311     # never gets here
 9312 
 9313 stmt-has-outputs?:  # line: (addr stream byte) -> result/eax: boolean
 9314     # . prologue
 9315     55/push-ebp
 9316     89/<- %ebp 4/r32/esp
 9317     # . save registers
 9318     51/push-ecx
 9319     # var word-slice/ecx: slice
 9320     68/push 0/imm32/end
 9321     68/push 0/imm32/start
 9322     89/<- %ecx 4/r32/esp
 9323     # result = false
 9324     b8/copy-to-eax 0/imm32/false
 9325     (rewind-stream *(ebp+8))
 9326     {
 9327       (next-mu-token *(ebp+8) %ecx)
 9328       # if slice-empty?(word-slice) break
 9329       (slice-empty? %ecx)
 9330       3d/compare-eax-and 0/imm32/false
 9331       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
 9332       0f 85/jump-if-!= break/disp32
 9333       # if slice-starts-with?(word-slice, '#') break
 9334       # . eax = *word-slice->start
 9335       8b/-> *ecx 0/r32/eax
 9336       8a/copy-byte *eax 0/r32/AL
 9337       81 4/subop/and %eax 0xff/imm32
 9338       # . if (eax == '#') break
 9339       3d/compare-eax-and 0x23/imm32/hash
 9340       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
 9341       0f 84/jump-if-= break/disp32
 9342       # if slice-equal?(word-slice, '<-') return true
 9343       (slice-equal? %ecx "<-")
 9344       3d/compare-eax-and 0/imm32/false
 9345       74/jump-if-= loop/disp8
 9346       b8/copy-to-eax 1/imm32/true
 9347     }
 9348 $stmt-has-outputs:end:
 9349     (rewind-stream *(ebp+8))
 9350     # . reclaim locals
 9351     81 0/subop/add %esp 8/imm32
 9352     # . restore registers
 9353     59/pop-to-ecx
 9354     # . epilogue
 9355     89/<- %esp 5/r32/ebp
 9356     5d/pop-to-ebp
 9357     c3/return
 9358 
 9359 # if 'name' starts with a digit, create a new literal var for it
 9360 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found
 9361 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)
 9362     # . prologue
 9363     55/push-ebp
 9364     89/<- %ebp 4/r32/esp
 9365     # . save registers
 9366     50/push-eax
 9367     51/push-ecx
 9368     56/push-esi
 9369     # esi = name
 9370     8b/-> *(ebp+8) 6/r32/esi
 9371     # if slice-empty?(name) abort
 9372     (slice-empty? %esi)  # => eax
 9373     3d/compare-eax-and 0/imm32/false
 9374     0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32
 9375     # var c/ecx: byte = *name->start
 9376     8b/-> *esi 1/r32/ecx
 9377     8a/copy-byte *ecx 1/r32/CL
 9378     81 4/subop/and %ecx 0xff/imm32
 9379     # if is-decimal-digit?(c) return new var(name)
 9380     {
 9381       (is-decimal-digit? %ecx)  # => eax
 9382       3d/compare-eax-and 0/imm32/false
 9383       74/jump-if-= break/disp8
 9384 $lookup-var-or-literal:literal:
 9385       (new-literal-integer Heap %esi *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 9386       eb/jump $lookup-var-or-literal:end/disp8
 9387     }
 9388     # else if (c == '"') return new var(name)
 9389     {
 9390       81 7/subop/compare %ecx 0x22/imm32/dquote
 9391       75/jump-if-!= break/disp8
 9392 $lookup-var-or-literal:literal-string:
 9393       (new-literal Heap %esi *(ebp+0x10))
 9394       eb/jump $lookup-var-or-literal:end/disp8
 9395     }
 9396     # otherwise return lookup-var(name, vars)
 9397     {
 9398 $lookup-var-or-literal:var:
 9399       (lookup-var %esi *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 9400     }
 9401 $lookup-var-or-literal:end:
 9402     # . restore registers
 9403     5e/pop-to-esi
 9404     59/pop-to-ecx
 9405     58/pop-to-eax
 9406     # . epilogue
 9407     89/<- %esp 5/r32/ebp
 9408     5d/pop-to-ebp
 9409     c3/return
 9410 
 9411 $lookup-var-or-literal:abort:
 9412     (write-buffered *(ebp+0x18) "fn ")
 9413     8b/-> *(ebp+0x14) 0/r32/eax
 9414     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9415     (write-buffered *(ebp+0x18) %eax)
 9416     (write-buffered *(ebp+0x18) ": empty variable!")
 9417     (flush *(ebp+0x18))
 9418     (stop *(ebp+0x1c) 1)
 9419     # never gets here
 9420 
 9421 # return first 'name' from the top (back) of 'vars' and abort if not found
 9422 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)
 9423     # . prologue
 9424     55/push-ebp
 9425     89/<- %ebp 4/r32/esp
 9426     # . save registers
 9427     50/push-eax
 9428     #
 9429     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 9430     # if (*out == 0) abort
 9431     8b/-> *(ebp+0x10) 0/r32/eax
 9432     81 7/subop/compare *eax 0/imm32
 9433     74/jump-if-= $lookup-var:abort/disp8
 9434 $lookup-var:end:
 9435     # . restore registers
 9436     58/pop-to-eax
 9437     # . epilogue
 9438     89/<- %esp 5/r32/ebp
 9439     5d/pop-to-ebp
 9440     c3/return
 9441 
 9442 $lookup-var:abort:
 9443     (write-buffered *(ebp+0x18) "fn ")
 9444     8b/-> *(ebp+0x14) 0/r32/eax
 9445     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9446     (write-buffered *(ebp+0x18) %eax)
 9447     (write-buffered *(ebp+0x18) ": unknown variable '")
 9448     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 9449     (write-buffered *(ebp+0x18) "'\n")
 9450     (flush *(ebp+0x18))
 9451     (stop *(ebp+0x1c) 1)
 9452     # never gets here
 9453 
 9454 # return first 'name' from the top (back) of 'vars', and 0/null if not found
 9455 # ensure that 'name' if in a register is the topmost variable in that register
 9456 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)
 9457     # pseudocode:
 9458     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
 9459     #   var min = vars->data
 9460     #   while curr >= min
 9461     #     var v: (handle var) = *curr
 9462     #     if v->name == name
 9463     #       return
 9464     #     curr -= 12
 9465     #
 9466     # . prologue
 9467     55/push-ebp
 9468     89/<- %ebp 4/r32/esp
 9469     # . save registers
 9470     50/push-eax
 9471     51/push-ecx
 9472     52/push-edx
 9473     53/push-ebx
 9474     56/push-esi
 9475     57/push-edi
 9476     # clear out
 9477     (zero-out *(ebp+0x10) *Handle-size)
 9478     # esi = vars
 9479     8b/-> *(ebp+0xc) 6/r32/esi
 9480     # ebx = vars->top
 9481     8b/-> *esi 3/r32/ebx
 9482     # if (vars->top > vars->size) abort
 9483     3b/compare<- *(esi+4) 0/r32/eax
 9484     0f 8f/jump-if-> $lookup-var-helper:error1/disp32
 9485     # var min/edx: (addr handle var) = vars->data
 9486     8d/copy-address *(esi+8) 2/r32/edx
 9487     # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
 9488     8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
 9489     # var var-in-reg/edi: 8 addrs
 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     68/push 0/imm32
 9496     68/push 0/imm32
 9497     68/push 0/imm32
 9498     89/<- %edi 4/r32/esp
 9499     {
 9500 $lookup-var-helper:loop:
 9501       # if (curr < min) return
 9502       39/compare %ebx 2/r32/edx
 9503       0f 82/jump-if-addr< break/disp32
 9504       # var v/ecx: (addr var) = lookup(*curr)
 9505       (lookup *ebx *(ebx+4))  # => eax
 9506       89/<- %ecx 0/r32/eax
 9507       # var vn/eax: (addr array byte) = lookup(v->name)
 9508       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 9509       # if (vn == name) return curr
 9510       (slice-equal? *(ebp+8) %eax)  # => eax
 9511       3d/compare-eax-and 0/imm32/false
 9512       {
 9513         74/jump-if-= break/disp8
 9514 $lookup-var-helper:found:
 9515         # var vr/eax: (addr array byte) = lookup(v->register)
 9516         (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 9517         3d/compare-eax-and 0/imm32
 9518         {
 9519           74/jump-if-= break/disp8
 9520 $lookup-var-helper:found-register:
 9521           # var reg/eax: int = get(Registers, vr)
 9522           (get Mu-registers %eax 0xc "Mu-registers")  # => eax
 9523           8b/-> *eax 0/r32/eax
 9524           # if (var-in-reg[reg]) error
 9525           8b/-> *(edi+eax<<2) 0/r32/eax
 9526           3d/compare-eax-and 0/imm32
 9527           0f 85/jump-if-!= $lookup-var-helper:error2/disp32
 9528         }
 9529 $lookup-var-helper:return:
 9530         # esi = out
 9531         8b/-> *(ebp+0x10) 6/r32/esi
 9532         # *out = *curr
 9533         8b/-> *ebx 0/r32/eax
 9534         89/<- *esi 0/r32/eax
 9535         8b/-> *(ebx+4) 0/r32/eax
 9536         89/<- *(esi+4) 0/r32/eax
 9537         # return
 9538         eb/jump $lookup-var-helper:end/disp8
 9539       }
 9540       # 'name' not yet found; update var-in-reg if v in register
 9541       # . var vr/eax: (addr array byte) = lookup(v->register)
 9542       (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 9543       # . if (var == 0) continue
 9544       3d/compare-eax-and 0/imm32
 9545       74/jump-if-= $lookup-var-helper:continue/disp8
 9546       # . var reg/eax: int = get(Registers, vr)
 9547       (get Mu-registers %eax 0xc "Mu-registers")  # => eax
 9548       8b/-> *eax 0/r32/eax
 9549       # . if (var-in-reg[reg] == 0) var-in-reg[reg] = v
 9550       81 7/subop/compare *(edi+eax<<2) 0/imm32
 9551       75/jump-if-!= $lookup-var-helper:continue/disp8
 9552       89/<- *(edi+eax<<2) 1/r32/ecx
 9553 $lookup-var-helper:continue:
 9554       # curr -= 12
 9555       81 5/subop/subtract %ebx 0xc/imm32
 9556       e9/jump loop/disp32
 9557     }
 9558 $lookup-var-helper:end:
 9559     # . reclaim locals
 9560     81 0/subop/add %esp 0x20/imm32
 9561     # . restore registers
 9562     5f/pop-to-edi
 9563     5e/pop-to-esi
 9564     5b/pop-to-ebx
 9565     5a/pop-to-edx
 9566     59/pop-to-ecx
 9567     58/pop-to-eax
 9568     # . epilogue
 9569     89/<- %esp 5/r32/ebp
 9570     5d/pop-to-ebp
 9571     c3/return
 9572 
 9573 $lookup-var-helper:error1:
 9574     (write-buffered *(ebp+0x18) "fn ")
 9575     8b/-> *(ebp+0x14) 0/r32/eax
 9576     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9577     (write-buffered *(ebp+0x18) %eax)
 9578     (write-buffered *(ebp+0x18) ": malformed stack when looking up '")
 9579     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 9580     (write-buffered *(ebp+0x18) "'\n")
 9581     (flush *(ebp+0x18))
 9582     (stop *(ebp+0x1c) 1)
 9583     # never gets here
 9584 
 9585 $lookup-var-helper:error2:
 9586     # eax contains the conflicting var at this point
 9587     (write-buffered *(ebp+0x18) "fn ")
 9588     50/push-eax
 9589     8b/-> *(ebp+0x14) 0/r32/eax
 9590     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9591     (write-buffered *(ebp+0x18) %eax)
 9592     58/pop-eax
 9593     (write-buffered *(ebp+0x18) ": register ")
 9594     50/push-eax
 9595     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
 9596     (write-buffered *(ebp+0x18) %eax)
 9597     58/pop-to-eax
 9598     (write-buffered *(ebp+0x18) " reads var '")
 9599     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 9600     (write-buffered *(ebp+0x18) "' after writing var '")
 9601     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9602     (write-buffered *(ebp+0x18) %eax)
 9603     (write-buffered *(ebp+0x18) "'\n")
 9604     (flush *(ebp+0x18))
 9605     (stop *(ebp+0x1c) 1)
 9606     # never gets here
 9607 
 9608 dump-vars:  # vars: (addr stack live-var)
 9609     # pseudocode:
 9610     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
 9611     #   var min = vars->data
 9612     #   while curr >= min
 9613     #     var v: (handle var) = *curr
 9614     #     print v
 9615     #     curr -= 12
 9616     #
 9617     # . prologue
 9618     55/push-ebp
 9619     89/<- %ebp 4/r32/esp
 9620     # . save registers
 9621     52/push-edx
 9622     53/push-ebx
 9623     56/push-esi
 9624     # esi = vars
 9625     8b/-> *(ebp+8) 6/r32/esi
 9626     # ebx = vars->top
 9627     8b/-> *esi 3/r32/ebx
 9628     # var min/edx: (addr handle var) = vars->data
 9629     8d/copy-address *(esi+8) 2/r32/edx
 9630     # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
 9631     8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
 9632     {
 9633 $dump-vars:loop:
 9634       # if (curr < min) return
 9635       39/compare %ebx 2/r32/edx
 9636       0f 82/jump-if-addr< break/disp32
 9637       #
 9638       (write-buffered Stderr "  var@")
 9639       (dump-var 2 %ebx)
 9640       # curr -= 12
 9641       81 5/subop/subtract %ebx 0xc/imm32
 9642       e9/jump loop/disp32
 9643     }
 9644 $dump-vars:end:
 9645     # . restore registers
 9646     5e/pop-to-esi
 9647     5b/pop-to-ebx
 9648     5a/pop-to-edx
 9649     # . epilogue
 9650     89/<- %esp 5/r32/ebp
 9651     5d/pop-to-ebp
 9652     c3/return
 9653 
 9654 == data
 9655 # Like Registers, but no esp or ebp
 9656 Mu-registers:  # (addr stream {(handle array byte), int})
 9657   # a table is a stream
 9658   0x48/imm32/write
 9659   0/imm32/read
 9660   0x48/imm32/length
 9661   # data
 9662   # it is perfectly ok to use fake alloc-ids -- as long as you never try to reclaim them
 9663   0x11/imm32/alloc-id $Mu-register-eax/imm32 0/imm32
 9664   0x11/imm32/alloc-id $Mu-register-ecx/imm32 1/imm32
 9665   0x11/imm32/alloc-id $Mu-register-edx/imm32 2/imm32
 9666   0x11/imm32/alloc-id $Mu-register-ebx/imm32 3/imm32
 9667   0x11/imm32/alloc-id $Mu-register-esi/imm32 6/imm32
 9668   0x11/imm32/alloc-id $Mu-register-edi/imm32 7/imm32
 9669 
 9670 $Mu-register-eax:
 9671   0x11/imm32/alloc-id
 9672   3/imm32/size
 9673   0x65/e 0x61/a 0x78/x
 9674 
 9675 $Mu-register-ecx:
 9676   0x11/imm32/alloc-id
 9677   3/imm32/size
 9678   0x65/e 0x63/c 0x78/x
 9679 
 9680 $Mu-register-edx:
 9681   0x11/imm32/alloc-id
 9682   3/imm32/size
 9683   0x65/e 0x64/d 0x78/x
 9684 
 9685 $Mu-register-ebx:
 9686   0x11/imm32/alloc-id
 9687   3/imm32/size
 9688   0x65/e 0x62/b 0x78/x
 9689 
 9690 $Mu-register-esi:
 9691   0x11/imm32/alloc-id
 9692   3/imm32/size
 9693   0x65/e 0x73/s 0x69/i
 9694 
 9695 $Mu-register-edi:
 9696   0x11/imm32/alloc-id
 9697   3/imm32/size
 9698   0x65/e 0x64/d 0x69/i
 9699 
 9700 == code
 9701 
 9702 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found
 9703 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)
 9704     # . prologue
 9705     55/push-ebp
 9706     89/<- %ebp 4/r32/esp
 9707     # . save registers
 9708     50/push-eax
 9709     #
 9710     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))  # arg order slightly different; 'fn' is deemphasized
 9711     {
 9712       # if (out != 0) return
 9713       8b/-> *(ebp+0x14) 0/r32/eax
 9714       81 7/subop/compare *eax 0/imm32
 9715       75/jump-if-!= break/disp8
 9716       # if name is one of fn's outputs, return it
 9717       (find-in-function-outputs *(ebp+0x10) *(ebp+8) *(ebp+0x14))
 9718       8b/-> *(ebp+0x14) 0/r32/eax
 9719       81 7/subop/compare *eax 0/imm32
 9720       # otherwise abort
 9721       0f 84/jump-if-= $lookup-or-define-var:abort/disp32
 9722     }
 9723 $lookup-or-define-var:end:
 9724     # . restore registers
 9725     58/pop-to-eax
 9726     # . epilogue
 9727     89/<- %esp 5/r32/ebp
 9728     5d/pop-to-ebp
 9729     c3/return
 9730 
 9731 $lookup-or-define-var:abort:
 9732     (write-buffered *(ebp+0x18) "unknown variable '")
 9733     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 9734     (write-buffered *(ebp+0x18) "'\n")
 9735     (flush *(ebp+0x18))
 9736     (stop *(ebp+0x1c) 1)
 9737     # never gets here
 9738 
 9739 find-in-function-outputs:  # fn: (addr function), name: (addr slice), out: (addr handle var)
 9740     # . prologue
 9741     55/push-ebp
 9742     89/<- %ebp 4/r32/esp
 9743     # . save registers
 9744     50/push-eax
 9745     51/push-ecx
 9746     # var curr/ecx: (addr list var) = lookup(fn->outputs)
 9747     8b/-> *(ebp+8) 1/r32/ecx
 9748     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
 9749     89/<- %ecx 0/r32/eax
 9750     # while curr != null
 9751     {
 9752       81 7/subop/compare %ecx 0/imm32
 9753       74/jump-if-= break/disp8
 9754       # var v/eax: (addr var) = lookup(curr->value)
 9755       (lookup *ecx *(ecx+4))  # List-value List-value => eax
 9756       # var s/eax: (addr array byte) = lookup(v->name)
 9757       (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9758       # if (s == name) return curr->value
 9759       (slice-equal? *(ebp+0xc) %eax)  # => eax
 9760       3d/compare-eax-and 0/imm32/false
 9761       {
 9762         74/jump-if-= break/disp8
 9763         # var edi = out
 9764         57/push-edi
 9765         8b/-> *(ebp+0x10) 7/r32/edi
 9766         # *out = curr->value
 9767         8b/-> *ecx 0/r32/eax
 9768         89/<- *edi 0/r32/eax
 9769         8b/-> *(ecx+4) 0/r32/eax
 9770         89/<- *(edi+4) 0/r32/eax
 9771         #
 9772         5f/pop-to-edi
 9773         eb/jump $find-in-function-outputs:end/disp8
 9774       }
 9775       # curr = curr->next
 9776       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
 9777       89/<- %ecx 0/r32/eax
 9778       #
 9779       eb/jump loop/disp8
 9780     }
 9781     b8/copy-to-eax 0/imm32
 9782 $find-in-function-outputs:end:
 9783     # . restore registers
 9784     59/pop-to-ecx
 9785     58/pop-to-eax
 9786     # . epilogue
 9787     89/<- %esp 5/r32/ebp
 9788     5d/pop-to-ebp
 9789     c3/return
 9790 
 9791 # push 'out' to 'vars' if not already there; it's assumed to be a fn output
 9792 maybe-define-var:  # out: (handle var), vars: (addr stack live-var)
 9793     # . prologue
 9794     55/push-ebp
 9795     89/<- %ebp 4/r32/esp
 9796     # . save registers
 9797     50/push-eax
 9798     # var out-addr/eax: (addr var)
 9799     (lookup *(ebp+8) *(ebp+0xc))  # => eax
 9800     #
 9801     (binding-exists? %eax *(ebp+0x10))  # => eax
 9802     3d/compare-eax-and 0/imm32/false
 9803     75/jump-if-!= $maybe-define-var:end/disp8
 9804     # otherwise update vars
 9805     (push *(ebp+0x10) *(ebp+8))
 9806     (push *(ebp+0x10) *(ebp+0xc))
 9807     (push *(ebp+0x10) 0)  # 'out' is always a fn output; never spill it
 9808 $maybe-define-var:end:
 9809     # . restore registers
 9810     58/pop-to-eax
 9811     # . epilogue
 9812     89/<- %esp 5/r32/ebp
 9813     5d/pop-to-ebp
 9814     c3/return
 9815 
 9816 # simpler version of lookup-var-helper
 9817 binding-exists?:  # target: (addr var), vars: (addr stack live-var) -> result/eax: boolean
 9818     # pseudocode:
 9819     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
 9820     #   var min = vars->data
 9821     #   while curr >= min
 9822     #     var v: (handle var) = *curr
 9823     #     if v->name == target->name
 9824     #       return true
 9825     #     curr -= 12
 9826     #   return false
 9827     #
 9828     # . prologue
 9829     55/push-ebp
 9830     89/<- %ebp 4/r32/esp
 9831     # . save registers
 9832     51/push-ecx
 9833     52/push-edx
 9834     56/push-esi
 9835     # var target-name/ecx: (addr array byte) = lookup(target->name)
 9836     8b/-> *(ebp+8) 0/r32/eax
 9837     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9838     89/<- %ecx 0/r32/eax
 9839     # esi = vars
 9840     8b/-> *(ebp+0xc) 6/r32/esi
 9841     # eax = vars->top
 9842     8b/-> *esi 0/r32/eax
 9843     # var min/edx: (addr handle var) = vars->data
 9844     8d/copy-address *(esi+8) 2/r32/edx
 9845     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
 9846     8d/copy-address *(esi+eax-4) 6/r32/esi  # vars + 8 + vars->type - 12
 9847     {
 9848 $binding-exists?:loop:
 9849       # if (curr < min) return
 9850       39/compare %esi 2/r32/edx
 9851       0f 82/jump-if-addr< break/disp32
 9852       # var v/eax: (addr var) = lookup(*curr)
 9853       (lookup *esi *(esi+4))  # => eax
 9854       # var vn/eax: (addr array byte) = lookup(v->name)
 9855       (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9856       # if (vn == target-name) return true
 9857       (string-equal? %ecx %eax)  # => eax
 9858       3d/compare-eax-and 0/imm32/false
 9859       75/jump-if-!= $binding-exists?:end/disp8  # eax already contains true
 9860       # curr -= 12
 9861       81 5/subop/subtract %esi 0xc/imm32
 9862       e9/jump loop/disp32
 9863     }
 9864     b8/copy-to-eax 0/imm32/false
 9865 $binding-exists?:end:
 9866     # . restore registers
 9867     5e/pop-to-esi
 9868     5a/pop-to-edx
 9869     59/pop-to-ecx
 9870     # . epilogue
 9871     89/<- %esp 5/r32/ebp
 9872     5d/pop-to-ebp
 9873     c3/return
 9874 
 9875 test-parse-mu-stmt:
 9876     # . prologue
 9877     55/push-ebp
 9878     89/<- %ebp 4/r32/esp
 9879     # setup
 9880     (clear-stream _test-input-stream)
 9881     (write _test-input-stream "increment n\n")
 9882     # var vars/ecx: (stack (addr var) 16)
 9883     81 5/subop/subtract %esp 0xc0/imm32
 9884     68/push 0xc0/imm32/size
 9885     68/push 0/imm32/top
 9886     89/<- %ecx 4/r32/esp
 9887     (clear-stack %ecx)
 9888     # var v/edx: (handle var)
 9889     68/push 0/imm32
 9890     68/push 0/imm32
 9891     89/<- %edx 4/r32/esp
 9892     # var s/eax: (handle array byte)
 9893     68/push 0/imm32
 9894     68/push 0/imm32
 9895     89/<- %eax 4/r32/esp
 9896     # v = new var("n")
 9897     (copy-array Heap "n" %eax)
 9898     (new-var Heap *eax *(eax+4) %edx)
 9899     #
 9900     (push %ecx *edx)
 9901     (push %ecx *(edx+4))
 9902     (push %ecx 0)
 9903     # var out/eax: (handle stmt)
 9904     68/push 0/imm32
 9905     68/push 0/imm32
 9906     89/<- %eax 4/r32/esp
 9907     # convert
 9908     (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
 9909     # var out-addr/edx: (addr stmt) = lookup(*out)
 9910     (lookup *eax *(eax+4))  # => eax
 9911     89/<- %edx 0/r32/eax
 9912     # out->tag
 9913     (check-ints-equal *edx 1 "F - test-parse-mu-stmt/tag")  # Stmt-tag is Stmt1
 9914     # out->operation
 9915     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
 9916     (check-strings-equal %eax "increment" "F - test-parse-mu-stmt/name")  # Stmt1-operation
 9917     # out->inouts->value->name
 9918     # . eax = out->inouts
 9919     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9920     # . eax = out->inouts->value
 9921     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9922     # . eax = out->inouts->value->name
 9923     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9924     # .
 9925     (check-strings-equal %eax "n" "F - test-parse-mu-stmt/inout:0")
 9926     # . epilogue
 9927     89/<- %esp 5/r32/ebp
 9928     5d/pop-to-ebp
 9929     c3/return
 9930 
 9931 test-parse-mu-stmt-with-comma:
 9932     # . prologue
 9933     55/push-ebp
 9934     89/<- %ebp 4/r32/esp
 9935     # setup
 9936     (clear-stream _test-input-stream)
 9937     (write _test-input-stream "copy-to n, 3\n")
 9938     # var vars/ecx: (stack (addr var) 16)
 9939     81 5/subop/subtract %esp 0xc0/imm32
 9940     68/push 0xc0/imm32/size
 9941     68/push 0/imm32/top
 9942     89/<- %ecx 4/r32/esp
 9943     (clear-stack %ecx)
 9944     # var v/edx: (handle var)
 9945     68/push 0/imm32
 9946     68/push 0/imm32
 9947     89/<- %edx 4/r32/esp
 9948     # var s/eax: (handle array byte)
 9949     68/push 0/imm32
 9950     68/push 0/imm32
 9951     89/<- %eax 4/r32/esp
 9952     # v = new var("n")
 9953     (copy-array Heap "n" %eax)
 9954     (new-var Heap *eax *(eax+4) %edx)
 9955     #
 9956     (push %ecx *edx)
 9957     (push %ecx *(edx+4))
 9958     (push %ecx 0)
 9959     # var out/eax: (handle stmt)
 9960     68/push 0/imm32
 9961     68/push 0/imm32
 9962     89/<- %eax 4/r32/esp
 9963     # convert
 9964     (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
 9965     # var out-addr/edx: (addr stmt) = lookup(*out)
 9966     (lookup *eax *(eax+4))  # => eax
 9967     89/<- %edx 0/r32/eax
 9968     # out->tag
 9969     (check-ints-equal *edx 1 "F - test-parse-mu-stmt-with-comma/tag")  # Stmt-tag is Stmt1
 9970     # out->operation
 9971     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
 9972     (check-strings-equal %eax "copy-to" "F - test-parse-mu-stmt-with-comma/name")  # Stmt1-operation
 9973     # out->inouts->value->name
 9974     # . eax = out->inouts
 9975     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9976     # . eax = out->inouts->value
 9977     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9978     # . eax = out->inouts->value->name
 9979     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9980     # .
 9981     (check-strings-equal %eax "n" "F - test-parse-mu-stmt-with-comma/inout:0")
 9982     # . epilogue
 9983     89/<- %esp 5/r32/ebp
 9984     5d/pop-to-ebp
 9985     c3/return
 9986 
 9987 new-var:  # ad: (addr allocation-descriptor), name: (handle array byte), out: (addr handle var)
 9988     # . prologue
 9989     55/push-ebp
 9990     89/<- %ebp 4/r32/esp
 9991     # . save registers
 9992     50/push-eax
 9993     51/push-ecx
 9994     # ecx = out
 9995     8b/-> *(ebp+0x14) 1/r32/ecx
 9996     #
 9997     (allocate *(ebp+8) *Var-size %ecx)
 9998     # var out-addr/eax: (addr var)
 9999     (lookup *ecx *(ecx+4))  # => eax
10000     # out-addr->name = name
10001     8b/-> *(ebp+0xc) 1/r32/ecx
10002     89/<- *eax 1/r32/ecx  # Var-name
10003     8b/-> *(ebp+0x10) 1/r32/ecx
10004     89/<- *(eax+4) 1/r32/ecx  # Var-name
10005 #?     (write-buffered Stderr "var ")
10006 #?     (lookup *(ebp+0xc) *(ebp+0x10))
10007 #?     (write-buffered Stderr %eax)
10008 #?     (write-buffered Stderr " at ")
10009 #?     8b/-> *(ebp+0x14) 1/r32/ecx
10010 #?     (lookup *ecx *(ecx+4))  # => eax
10011 #?     (write-int32-hex-buffered Stderr %eax)
10012 #?     (write-buffered Stderr Newline)
10013 #?     (flush Stderr)
10014 $new-var:end:
10015     # . restore registers
10016     59/pop-to-ecx
10017     58/pop-to-eax
10018     # . epilogue
10019     89/<- %esp 5/r32/ebp
10020     5d/pop-to-ebp
10021     c3/return
10022 
10023 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)
10024     # . prologue
10025     55/push-ebp
10026     89/<- %ebp 4/r32/esp
10027     # . save registers
10028     50/push-eax
10029     51/push-ecx
10030     # if (!is-hex-int?(name)) abort
10031     (is-hex-int? *(ebp+0xc))  # => eax
10032     3d/compare-eax-and 0/imm32/false
10033     0f 84/jump-if-= $new-literal-integer:abort/disp32
10034     # a little more error-checking
10035     (check-mu-hex-int *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c))
10036     # out = new var(s)
10037     (new-var-from-slice *(ebp+8) *(ebp+0xc) *(ebp+0x10))
10038     # var out-addr/ecx: (addr var) = lookup(*out)
10039     8b/-> *(ebp+0x10) 0/r32/eax
10040     (lookup *eax *(eax+4))  # => eax
10041     89/<- %ecx 0/r32/eax
10042     # out-addr->block-depth = *Curr-block-depth
10043     8b/-> *Curr-block-depth 0/r32/eax
10044     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
10045     # out-addr->type = new tree()
10046     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
10047     (allocate *(ebp+8) *Type-tree-size %eax)
10048     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
10049     c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
10050     # nothing else to do; default type is 'literal'
10051 $new-literal-integer:end:
10052     # . reclaim locals
10053     81 0/subop/add %esp 8/imm32
10054     # . restore registers
10055     59/pop-to-ecx
10056     58/pop-to-eax
10057     # . epilogue
10058     89/<- %esp 5/r32/ebp
10059     5d/pop-to-ebp
10060     c3/return
10061 
10062 $new-literal-integer:abort:
10063     (write-buffered *(ebp+0x18) "fn ")
10064     8b/-> *(ebp+0x14) 0/r32/eax
10065     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10066     (write-buffered *(ebp+0x18) %eax)
10067     (write-buffered *(ebp+0x18) ": variable '")
10068     (write-slice-buffered *(ebp+0x18) *(ebp+0xc))
10069     (write-buffered *(ebp+0x18) "' cannot begin with a digit (or do you have a typo in a number?)\n")
10070     (flush *(ebp+0x18))
10071     (stop *(ebp+0x1c) 1)
10072     # never gets here
10073 
10074 # precondition: name is a valid hex integer; require a '0x' prefix
10075 check-mu-hex-int:  # name: (addr slice), err: (addr buffered-file), ed: (addr exit-descriptor)
10076     # . prologue
10077     55/push-ebp
10078     89/<- %ebp 4/r32/esp
10079     # . save registers
10080     50/push-eax
10081     51/push-ecx
10082     52/push-edx
10083     #
10084     8b/-> *(ebp+8) 1/r32/ecx
10085     # var start/ecx: (addr byte) = name->start
10086     8b/-> *(ecx+4) 2/r32/edx
10087     # var end/ecx: (addr byte) = name->end
10088     8b/-> *ecx 1/r32/ecx
10089     # var len/eax: int = name->end - name->start
10090     89/<- %eax 2/r32/edx
10091     29/subtract-from %eax 1/r32/ecx
10092     # if (len <= 1) return
10093     3d/compare-eax-with 1/imm32
10094     0f 8e/jump-if-<= $check-mu-hex-int:end/disp32
10095 $check-mu-hex-int:length->-1:
10096     # if slice-starts-with?("0x") return
10097     (slice-starts-with? *(ebp+8) "0x")  # => eax
10098     3d/compare-eax-with 0/imm32/false
10099     75/jump-if-!= $check-mu-hex-int:end/disp8
10100 $check-mu-hex-int:abort:
10101     # otherwise abort
10102     (write-buffered *(ebp+0xc) "literal integers are always hex in Mu; either start '")
10103     (write-slice-buffered *(ebp+0xc) *(ebp+8))
10104     (write-buffered *(ebp+0xc) "' with a '0x' to be unambiguous, or convert it to decimal.\n")
10105     (flush *(ebp+0xc))
10106     (stop *(ebp+0x10) 1)
10107 $check-mu-hex-int:end:
10108     # . restore registers
10109     5a/pop-to-edx
10110     59/pop-to-ecx
10111     58/pop-to-eax
10112     # . epilogue
10113     89/<- %esp 5/r32/ebp
10114     5d/pop-to-ebp
10115     c3/return
10116 
10117 new-literal:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
10118     # . prologue
10119     55/push-ebp
10120     89/<- %ebp 4/r32/esp
10121     # . save registers
10122     50/push-eax
10123     51/push-ecx
10124     # var s/ecx: (handle array byte)
10125     68/push 0/imm32
10126     68/push 0/imm32
10127     89/<- %ecx 4/r32/esp
10128     # s = slice-to-string(name)
10129     (slice-to-string Heap *(ebp+0xc) %ecx)
10130     # allocate to out
10131     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
10132     # var out-addr/ecx: (addr var) = lookup(*out)
10133     8b/-> *(ebp+0x10) 1/r32/ecx
10134     (lookup *ecx *(ecx+4))  # => eax
10135     89/<- %ecx 0/r32/eax
10136     # out-addr->block-depth = *Curr-block-depth
10137     8b/-> *Curr-block-depth 0/r32/eax
10138     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
10139     # out-addr->type/eax = new type
10140     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
10141     (allocate *(ebp+8) *Type-tree-size %eax)
10142     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
10143     # nothing else to do; default type is 'literal'
10144     c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
10145 $new-literal:end:
10146     # . reclaim locals
10147     81 0/subop/add %esp 8/imm32
10148     # . restore registers
10149     59/pop-to-ecx
10150     58/pop-to-eax
10151     # . epilogue
10152     89/<- %esp 5/r32/ebp
10153     5d/pop-to-ebp
10154     c3/return
10155 
10156 new-var-from-slice:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
10157     # . prologue
10158     55/push-ebp
10159     89/<- %ebp 4/r32/esp
10160     # . save registers
10161     51/push-ecx
10162     # var tmp/ecx: (handle array byte)
10163     68/push 0/imm32
10164     68/push 0/imm32
10165     89/<- %ecx 4/r32/esp
10166     # tmp = slice-to-string(name)
10167     (slice-to-string Heap *(ebp+0xc) %ecx)
10168     # out = new-var(tmp)
10169     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
10170 $new-var-from-slice:end:
10171     # . reclaim locals
10172     81 0/subop/add %esp 8/imm32
10173     # . restore registers
10174     59/pop-to-ecx
10175     # . epilogue
10176     89/<- %esp 5/r32/ebp
10177     5d/pop-to-ebp
10178     c3/return
10179 
10180 new-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
10181     # . prologue
10182     55/push-ebp
10183     89/<- %ebp 4/r32/esp
10184     # . save registers
10185     50/push-eax
10186     51/push-ecx
10187     #
10188     (allocate *(ebp+8) *Stmt-size *(ebp+0x14))
10189     # var out-addr/eax: (addr stmt) = lookup(*out)
10190     8b/-> *(ebp+0x14) 0/r32/eax
10191     (lookup *eax *(eax+4))  # => eax
10192     # out-addr->tag = stmt
10193     c7 0/subop/copy *eax 2/imm32/tag/var-on-stack  # Stmt-tag
10194     # result->var = var
10195     8b/-> *(ebp+0xc) 1/r32/ecx
10196     89/<- *(eax+4) 1/r32/ecx  # Vardef-var
10197     8b/-> *(ebp+0x10) 1/r32/ecx
10198     89/<- *(eax+8) 1/r32/ecx  # Vardef-var
10199 $new-var-def:end:
10200     # . restore registers
10201     59/pop-to-ecx
10202     58/pop-to-eax
10203     # . epilogue
10204     89/<- %esp 5/r32/ebp
10205     5d/pop-to-ebp
10206     c3/return
10207 
10208 new-reg-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
10209     # . prologue
10210     55/push-ebp
10211     89/<- %ebp 4/r32/esp
10212     # . save registers
10213     50/push-eax
10214     # eax = out
10215     8b/-> *(ebp+0x14) 0/r32/eax
10216     #
10217     (allocate *(ebp+8) *Stmt-size %eax)
10218     # var out-addr/eax: (addr stmt) = lookup(*out)
10219     (lookup *eax *(eax+4))  # => eax
10220     # set tag
10221     c7 0/subop/copy *eax 3/imm32/tag/var-in-register  # Stmt-tag
10222     # set output
10223     8d/copy-address *(eax+0x14) 0/r32/eax  # Regvardef-outputs
10224     (append-stmt-var Heap  *(ebp+0xc) *(ebp+0x10)  0 0  0  %eax)
10225 $new-reg-var-def:end:
10226     # . restore registers
10227     58/pop-to-eax
10228     # . epilogue
10229     89/<- %esp 5/r32/ebp
10230     5d/pop-to-ebp
10231     c3/return
10232 
10233 append-list:  # ad: (addr allocation-descriptor), value: (handle _type), list: (handle list _type), out: (addr handle list _type)
10234     # . prologue
10235     55/push-ebp
10236     89/<- %ebp 4/r32/esp
10237     # . save registers
10238     50/push-eax
10239     51/push-ecx
10240     57/push-edi
10241     # edi = out
10242     8b/-> *(ebp+0x1c) 7/r32/edi
10243     # *out = new list
10244     (allocate *(ebp+8) *List-size %edi)
10245     # var out-addr/edi: (addr list _type) = lookup(*out)
10246     (lookup *edi *(edi+4))  # => eax
10247     89/<- %edi 0/r32/eax
10248     # out-addr->value = value
10249     8b/-> *(ebp+0xc) 0/r32/eax
10250     89/<- *edi 0/r32/eax  # List-value
10251     8b/-> *(ebp+0x10) 0/r32/eax
10252     89/<- *(edi+4) 0/r32/eax  # List-value
10253     # if (list == null) return
10254     81 7/subop/compare *(ebp+0x14) 0/imm32
10255     74/jump-if-= $append-list:end/disp8
10256     # otherwise append
10257 $append-list:non-empty-list:
10258     # var curr/eax: (addr list _type) = lookup(list)
10259     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
10260     # while (curr->next != null) curr = curr->next
10261     {
10262       81 7/subop/compare *(eax+8) 0/imm32  # List-next
10263       74/jump-if-= break/disp8
10264       # curr = lookup(curr->next)
10265       (lookup *(eax+8) *(eax+0xc))  # List-next, List-next => eax
10266       #
10267       eb/jump loop/disp8
10268     }
10269     # edi = out
10270     8b/-> *(ebp+0x1c) 7/r32/edi
10271     # curr->next = out
10272     8b/-> *edi 1/r32/ecx
10273     89/<- *(eax+8) 1/r32/ecx  # List-next
10274     8b/-> *(edi+4) 1/r32/ecx
10275     89/<- *(eax+0xc) 1/r32/ecx  # List-next
10276     # out = list
10277     8b/-> *(ebp+0x14) 1/r32/ecx
10278     89/<- *edi 1/r32/ecx
10279     8b/-> *(ebp+0x18) 1/r32/ecx
10280     89/<- *(edi+4) 1/r32/ecx
10281 $append-list:end:
10282     # . restore registers
10283     5f/pop-to-edi
10284     59/pop-to-ecx
10285     58/pop-to-eax
10286     # . epilogue
10287     89/<- %esp 5/r32/ebp
10288     5d/pop-to-ebp
10289     c3/return
10290 
10291 append-stmt-var:  # ad: (addr allocation-descriptor), v: (handle var), vars: (handle stmt-var), is-deref?: boolean, out: (addr handle stmt-var)
10292     # . prologue
10293     55/push-ebp
10294     89/<- %ebp 4/r32/esp
10295     # . save registers
10296     50/push-eax
10297     51/push-ecx
10298     57/push-edi
10299     # edi = out
10300     8b/-> *(ebp+0x20) 7/r32/edi
10301     # out = new stmt-var
10302     (allocate *(ebp+8) *Stmt-var-size %edi)
10303     # var out-addr/ecx: (addr stmt-var) = lookup(*out)
10304     (lookup *edi *(edi+4))  # => eax
10305     89/<- %ecx 0/r32/eax
10306     # out-addr->value = v
10307     8b/-> *(ebp+0xc) 0/r32/eax
10308     89/<- *ecx 0/r32/eax  # Stmt-var-value
10309     8b/-> *(ebp+0x10) 0/r32/eax
10310     89/<- *(ecx+4) 0/r32/eax  # Stmt-var-value
10311     # out-addr->is-deref? = is-deref?
10312     8b/-> *(ebp+0x1c) 0/r32/eax
10313     89/<- *(ecx+0x10) 0/r32/eax  # Stmt-var-is-deref
10314     # if (vars == null) return result
10315     81 7/subop/compare *(ebp+0x14) 0/imm32/null
10316     74/jump-if-= $append-stmt-var:end/disp8
10317     # otherwise append
10318     # var curr/eax: (addr stmt-var) = lookup(vars)
10319     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
10320     # while (curr->next != null) curr = curr->next
10321     {
10322       81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
10323       74/jump-if-= break/disp8
10324       # curr = lookup(curr->next)
10325       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next, Stmt-var-next => eax
10326       #
10327       eb/jump loop/disp8
10328     }
10329     # curr->next = out
10330     8b/-> *edi 1/r32/ecx
10331     89/<- *(eax+8) 1/r32/ecx  # Stmt-var-next
10332     8b/-> *(edi+4) 1/r32/ecx
10333     89/<- *(eax+0xc) 1/r32/ecx  # Stmt-var-next
10334     # out = vars
10335     8b/-> *(ebp+0x14) 1/r32/ecx
10336     89/<- *edi 1/r32/ecx
10337     8b/-> *(ebp+0x18) 1/r32/ecx
10338     89/<- *(edi+4) 1/r32/ecx
10339 $append-stmt-var:end:
10340     # . restore registers
10341     5f/pop-to-edi
10342     59/pop-to-ecx
10343     58/pop-to-eax
10344     # . epilogue
10345     89/<- %esp 5/r32/ebp
10346     5d/pop-to-ebp
10347     c3/return
10348 
10349 append-to-block:  # ad: (addr allocation-descriptor), block: (addr block), x: (handle stmt)
10350     # . prologue
10351     55/push-ebp
10352     89/<- %ebp 4/r32/esp
10353     # . save registers
10354     50/push-eax
10355     56/push-esi
10356     # esi = block
10357     8b/-> *(ebp+0xc) 6/r32/esi
10358     # block->stmts = append(x, block->stmts)
10359     8d/copy-address *(esi+4) 0/r32/eax  # Block-stmts
10360     (append-list *(ebp+8)  *(ebp+0x10) *(ebp+0x14)  *(esi+4) *(esi+8)  %eax)  # ad, x, x, Block-stmts, Block-stmts
10361 $append-to-block:end:
10362     # . restore registers
10363     5e/pop-to-esi
10364     58/pop-to-eax
10365     # . epilogue
10366     89/<- %esp 5/r32/ebp
10367     5d/pop-to-ebp
10368     c3/return
10369 
10370 ## Parsing types
10371 # We need to create metadata on user-defined types, and we need to use this
10372 # metadata as we parse instructions.
10373 # However, we also want to allow types to be used before their definitions.
10374 # This means we can't ever assume any type data structures exist.
10375 
10376 lookup-or-create-constant:  # container: (addr stmt-var), field-name: (addr slice), out: (addr handle var)
10377     # . prologue
10378     55/push-ebp
10379     89/<- %ebp 4/r32/esp
10380     # . save registers
10381     50/push-eax
10382     56/push-esi
10383     # var container-type/esi: type-id
10384     (container-type *(ebp+8))  # => eax
10385     89/<- %esi 0/r32/eax
10386     # var tmp/eax: (handle typeinfo) = find-or-create-typeinfo(container-type)
10387     68/push 0/imm32
10388     68/push 0/imm32
10389     89/<- %eax 4/r32/esp
10390     (find-or-create-typeinfo %esi %eax)
10391     # var tmp-addr/eax: (addr typeinfo) = lookup(tmp)
10392     (lookup *eax *(eax+4))  # => eax
10393     # result = find-or-create-typeinfo-output-var(typeinfo, field-name)
10394 #?     (write-buffered Stderr "constant: ")
10395 #?     (write-slice-buffered Stderr *(ebp+0xc))
10396 #?     (write-buffered Stderr Newline)
10397 #?     (flush Stderr)
10398     (find-or-create-typeinfo-output-var %eax *(ebp+0xc) *(ebp+0x10))
10399 #?     8b/-> *(ebp+0x10) 0/r32/eax
10400 #?     (write-buffered Stderr "@")
10401 #?     (lookup *eax *(eax+4))
10402 #?     (write-int32-hex-buffered Stderr %eax)
10403 #?     (lookup *eax *(eax+4))
10404 #?     (write-buffered Stderr %eax)
10405 #?     (write-buffered Stderr Newline)
10406 #?     (flush Stderr)
10407 #?     (write-buffered Stderr "offset: ")
10408 #?     8b/-> *(eax+0x14) 0/r32/eax
10409 #?     (write-int32-hex-buffered Stderr %eax)
10410 #?     (write-buffered Stderr Newline)
10411 #?     (flush Stderr)
10412 $lookup-or-create-constant:end:
10413     # . reclaim locals
10414     81 0/subop/add %esp 8/imm32
10415     # . restore registers
10416     5e/pop-to-esi
10417     58/pop-to-eax
10418     # . epilogue
10419     89/<- %esp 5/r32/ebp
10420     5d/pop-to-ebp
10421     c3/return
10422 
10423 # if addr var:
10424 #   container->var->type->right->left->value
10425 # otherwise
10426 #   container->var->type->value
10427 container-type:  # container: (addr stmt-var) -> result/eax: type-id
10428     # . prologue
10429     55/push-ebp
10430     89/<- %ebp 4/r32/esp
10431     #
10432     8b/-> *(ebp+8) 0/r32/eax
10433     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10434     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
10435     {
10436       81 7/subop/compare *(eax+8) 0/imm32  # Type-tree-right
10437       74/jump-if-= break/disp8
10438       (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
10439       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
10440     }
10441     8b/-> *(eax+4) 0/r32/eax  # Type-tree-value
10442 $container-type:end:
10443     # . epilogue
10444     89/<- %esp 5/r32/ebp
10445     5d/pop-to-ebp
10446     c3/return
10447 
10448 is-container?:  # t: type-id -> result/eax: boolean
10449     # . prologue
10450     55/push-ebp
10451     89/<- %ebp 4/r32/esp
10452     #
10453     8b/-> *(ebp+8) 0/r32/eax
10454     c1/shift 4/subop/left %eax 2/imm8
10455     3b/compare 0/r32/eax *Primitive-type-ids
10456     0f 9d/set-if->= %al
10457     81 4/subop/and %eax 0xff/imm32
10458 $is-container?:end:
10459     # . epilogue
10460     89/<- %esp 5/r32/ebp
10461     5d/pop-to-ebp
10462     c3/return
10463 
10464 find-or-create-typeinfo:  # t: type-id, out: (addr handle typeinfo)
10465     # . prologue
10466     55/push-ebp
10467     89/<- %ebp 4/r32/esp
10468     # . save registers
10469     50/push-eax
10470     51/push-ecx
10471     52/push-edx
10472     57/push-edi
10473     # edi = out
10474     8b/-> *(ebp+0xc) 7/r32/edi
10475     # var fields/ecx: (handle table (handle array byte) (handle typeinfo-entry))
10476     68/push 0/imm32
10477     68/push 0/imm32
10478     89/<- %ecx 4/r32/esp
10479     # find-typeinfo(t, out)
10480     (find-typeinfo *(ebp+8) %edi)
10481     {
10482       # if (*out != 0) break
10483       81 7/subop/compare *edi 0/imm32
10484       0f 85/jump-if-!= break/disp32
10485 $find-or-create-typeinfo:create:
10486       # *out = allocate
10487       (allocate Heap *Typeinfo-size %edi)
10488       # var tmp/eax: (addr typeinfo) = lookup(*out)
10489       (lookup *edi *(edi+4))  # => eax
10490 #?     (write-buffered Stderr "created typeinfo at ")
10491 #?     (write-int32-hex-buffered Stderr %eax)
10492 #?     (write-buffered Stderr " for type-id ")
10493 #?     (write-int32-hex-buffered Stderr *(ebp+8))
10494 #?     (write-buffered Stderr Newline)
10495 #?     (flush Stderr)
10496       # tmp->id = t
10497       8b/-> *(ebp+8) 2/r32/edx
10498       89/<- *eax 2/r32/edx  # Typeinfo-id
10499       # tmp->fields = new table
10500       # . fields = new table
10501       (new-stream Heap 0x40 *Typeinfo-fields-row-size %ecx)
10502       # . tmp->fields = fields
10503       8b/-> *ecx 2/r32/edx
10504       89/<- *(eax+4) 2/r32/edx  # Typeinfo-fields
10505       8b/-> *(ecx+4) 2/r32/edx
10506       89/<- *(eax+8) 2/r32/edx  # Typeinfo-fields
10507       # tmp->next = Program->types
10508       8b/-> *_Program-types 1/r32/ecx
10509       89/<- *(eax+0x10) 1/r32/ecx  # Typeinfo-next
10510       8b/-> *_Program-types->payload 1/r32/ecx
10511       89/<- *(eax+0x14) 1/r32/ecx  # Typeinfo-next
10512       # Program->types = out
10513       8b/-> *edi 1/r32/ecx
10514       89/<- *_Program-types 1/r32/ecx
10515       8b/-> *(edi+4) 1/r32/ecx
10516       89/<- *_Program-types->payload 1/r32/ecx
10517     }
10518 $find-or-create-typeinfo:end:
10519     # . reclaim locals
10520     81 0/subop/add %esp 8/imm32
10521     # . restore registers
10522     5f/pop-to-edi
10523     5a/pop-to-edx
10524     59/pop-to-ecx
10525     58/pop-to-eax
10526     # . epilogue
10527     89/<- %esp 5/r32/ebp
10528     5d/pop-to-ebp
10529     c3/return
10530 
10531 find-typeinfo:  # t: type-id, out: (addr handle typeinfo)
10532     # . prologue
10533     55/push-ebp
10534     89/<- %ebp 4/r32/esp
10535     # . save registers
10536     50/push-eax
10537     51/push-ecx
10538     52/push-edx
10539     57/push-edi
10540     # ecx = t
10541     8b/-> *(ebp+8) 1/r32/ecx
10542     # edi = out
10543     8b/-> *(ebp+0xc) 7/r32/edi
10544     # *out = Program->types
10545     8b/-> *_Program-types 0/r32/eax
10546     89/<- *edi 0/r32/eax
10547     8b/-> *_Program-types->payload 0/r32/eax
10548     89/<- *(edi+4) 0/r32/eax
10549     {
10550 $find-typeinfo:loop:
10551       # if (*out == 0) break
10552       81 7/subop/compare *edi 0/imm32
10553       74/jump-if-= break/disp8
10554 $find-typeinfo:check:
10555       # var tmp/eax: (addr typeinfo) = lookup(*out)
10556       (lookup *edi *(edi+4))  # => eax
10557       # if (tmp->id == t) break
10558       39/compare *eax 1/r32/ecx  # Typeinfo-id
10559       74/jump-if-= break/disp8
10560 $find-typeinfo:continue:
10561       # *out = tmp->next
10562       8b/-> *(eax+0x10) 2/r32/edx  # Typeinfo-next
10563       89/<- *edi 2/r32/edx
10564       8b/-> *(eax+0x14) 2/r32/edx  # Typeinfo-next
10565       89/<- *(edi+4) 2/r32/edx
10566       #
10567       eb/jump loop/disp8
10568     }
10569 $find-typeinfo:end:
10570     # . restore registers
10571     5f/pop-to-edi
10572     5a/pop-to-edx
10573     59/pop-to-ecx
10574     58/pop-to-eax
10575     # . epilogue
10576     89/<- %esp 5/r32/ebp
10577     5d/pop-to-ebp
10578     c3/return
10579 
10580 find-or-create-typeinfo-output-var:  # T: (addr typeinfo), f: (addr slice), out: (addr handle var)
10581     # . prologue
10582     55/push-ebp
10583     89/<- %ebp 4/r32/esp
10584     # . save registers
10585     50/push-eax
10586     52/push-edx
10587     57/push-edi
10588     # var dest/edi: (handle typeinfo-entry)
10589     68/push 0/imm32
10590     68/push 0/imm32
10591     89/<- %edi 4/r32/esp
10592     # find-or-create-typeinfo-fields(T, f, dest)
10593     (find-or-create-typeinfo-fields *(ebp+8) *(ebp+0xc) %edi)
10594     # var dest-addr/edi: (addr typeinfo-entry) = lookup(dest)
10595     (lookup *edi *(edi+4))  # => eax
10596     89/<- %edi 0/r32/eax
10597     # if dest-addr->output-var doesn't exist, create it
10598     {
10599       81 7/subop/compare *(edi+0xc) 0/imm32  # Typeinfo-entry-output-var
10600       0f 85/jump-if-!= break/disp32
10601       # dest-addr->output-var = new var(dummy name, type, -1 offset)
10602       # . var name/eax: (handle array byte) = "field"
10603       68/push 0/imm32
10604       68/push 0/imm32
10605       89/<- %eax 4/r32/esp
10606       (slice-to-string Heap *(ebp+0xc) %eax)
10607       # . new var
10608       8d/copy-address *(edi+0xc) 2/r32/edx
10609       (new-var Heap  *eax *(eax+4)  %edx)
10610       # . reclaim name
10611       81 0/subop/add %esp 8/imm32
10612       # var result/edx: (addr var) = lookup(dest-addr->output-var)
10613       (lookup *(edi+0xc) *(edi+0x10))  # => eax
10614       89/<- %edx 0/r32/eax
10615       # result->type = new constant type
10616       8d/copy-address *(edx+8) 0/r32/eax  # Var-type
10617       (allocate Heap *Type-tree-size %eax)
10618       (lookup *(edx+8) *(edx+0xc))  # => eax
10619       c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
10620       c7 0/subop/copy *(eax+4) 6/imm32/constant  # Type-tree-value
10621       c7 0/subop/copy *(eax+8) 0/imm32  # Type-tree-left
10622       c7 0/subop/copy *(eax+0xc) 0/imm32  # Type-tree-right
10623       c7 0/subop/copy *(eax+0x10) 0/imm32  # Type-tree-right
10624       # result->offset isn't filled out yet
10625       c7 0/subop/copy *(edx+0x14) -1/imm32/uninitialized  # Var-offset
10626     }
10627     # out = dest-addr->output-var
10628     8b/-> *(ebp+0x10) 2/r32/edx
10629     8b/-> *(edi+0xc) 0/r32/eax  # Typeinfo-entry-output-var
10630     89/<- *edx 0/r32/eax
10631     8b/-> *(edi+0x10) 0/r32/eax  # Typeinfo-entry-output-var
10632     89/<- *(edx+4) 0/r32/eax
10633 $find-or-create-typeinfo-output-var:end:
10634     # . reclaim locals
10635     81 0/subop/add %esp 8/imm32
10636     # . restore registers
10637     5f/pop-to-edi
10638     5a/pop-to-edx
10639     58/pop-to-eax
10640     # . epilogue
10641     89/<- %esp 5/r32/ebp
10642     5d/pop-to-ebp
10643     c3/return
10644 
10645 find-or-create-typeinfo-fields:  # T: (addr typeinfo), f: (addr slice), out: (addr handle typeinfo-entry)
10646     # . prologue
10647     55/push-ebp
10648     89/<- %ebp 4/r32/esp
10649     # . save registers
10650     50/push-eax
10651     56/push-esi
10652     57/push-edi
10653     # eax = lookup(T->fields)
10654     8b/-> *(ebp+8) 0/r32/eax
10655     (lookup *(eax+4) *(eax+8))  # Typeinfo-fields Typeinfo-fields => eax
10656     # edi = out
10657     8b/-> *(ebp+0x10) 7/r32/edi
10658     # var src/esi: (addr handle typeinfo-entry) = get-or-insert-slice(T->fields, f)
10659     (get-or-insert-slice %eax *(ebp+0xc) *Typeinfo-fields-row-size Heap)  # => eax
10660     89/<- %esi 0/r32/eax
10661     # if src doesn't exist, allocate it
10662     {
10663       81 7/subop/compare *esi 0/imm32
10664       75/jump-if-!= break/disp8
10665       (allocate Heap *Typeinfo-entry-size %esi)
10666 #?       (write-buffered Stderr "handle at ")
10667 #?       (write-int32-hex-buffered Stderr %esi)
10668 #?       (write-buffered Stderr ": ")
10669 #?       (write-int32-hex-buffered Stderr *esi)
10670 #?       (write-buffered Stderr " ")
10671 #?       (write-int32-hex-buffered Stderr *(esi+4))
10672 #?       (write-buffered Stderr Newline)
10673 #?       (flush Stderr)
10674 #?       (lookup *esi *(esi+4))
10675 #?       (write-buffered Stderr "created typeinfo fields at ")
10676 #?       (write-int32-hex-buffered Stderr %esi)
10677 #?       (write-buffered Stderr " for ")
10678 #?       (write-int32-hex-buffered Stderr *(ebp+8))
10679 #?       (write-buffered Stderr Newline)
10680 #?       (flush Stderr)
10681     }
10682     # *out = src
10683     # . *edi = *src
10684     8b/-> *esi 0/r32/eax
10685     89/<- *edi 0/r32/eax
10686     8b/-> *(esi+4) 0/r32/eax
10687     89/<- *(edi+4) 0/r32/eax
10688 $find-or-create-typeinfo-fields:end:
10689     # . restore registers
10690     5f/pop-to-edi
10691     5e/pop-to-esi
10692     58/pop-to-eax
10693     # . epilogue
10694     89/<- %esp 5/r32/ebp
10695     5d/pop-to-ebp
10696     c3/return
10697 
10698 populate-mu-type:  # in: (addr stream byte), t: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
10699     # pseudocode:
10700     #   var line: (stream byte 512)
10701     #   curr-index = 0
10702     #   while true
10703     #     clear-stream(line)
10704     #     read-line-buffered(in, line)
10705     #     if line->write == 0
10706     #       abort
10707     #     word-slice = next-mu-token(line)
10708     #     if slice-empty?(word-slice)               # end of line
10709     #       continue
10710     #     if slice-equal?(word-slice, "}")
10711     #       break
10712     #     var v: (handle var) = parse-var-with-type(word-slice, line)
10713     #     var r: (handle typeinfo-fields) = find-or-create-typeinfo-fields(t, word-slice/v->name)
10714     #     TODO: ensure that r->first is null
10715     #     r->index = curr-index
10716     #     curr-index++
10717     #     r->input-var = v
10718     #     if r->output-var == 0
10719     #       r->output-var = new literal
10720     #     TODO: ensure nothing else in line
10721     # t->total-size-in-bytes = -2 (not yet initialized)
10722     #
10723     # . prologue
10724     55/push-ebp
10725     89/<- %ebp 4/r32/esp
10726     # var curr-index: int at *(ebp-4)
10727     68/push 0/imm32
10728     # . save registers
10729     50/push-eax
10730     51/push-ecx
10731     52/push-edx
10732     53/push-ebx
10733     56/push-esi
10734     57/push-edi
10735     # edi = t
10736     8b/-> *(ebp+0xc) 7/r32/edi
10737     # var line/ecx: (stream byte 512)
10738     81 5/subop/subtract %esp 0x200/imm32
10739     68/push 0x200/imm32/size
10740     68/push 0/imm32/read
10741     68/push 0/imm32/write
10742     89/<- %ecx 4/r32/esp
10743     # var word-slice/edx: slice
10744     68/push 0/imm32/end
10745     68/push 0/imm32/start
10746     89/<- %edx 4/r32/esp
10747     # var v/esi: (handle var)
10748     68/push 0/imm32
10749     68/push 0/imm32
10750     89/<- %esi 4/r32/esp
10751     # var r/ebx: (handle typeinfo-entry)
10752     68/push 0/imm32
10753     68/push 0/imm32
10754     89/<- %ebx 4/r32/esp
10755     {
10756 $populate-mu-type:line-loop:
10757       (clear-stream %ecx)
10758       (read-line-buffered *(ebp+8) %ecx)
10759       # if (line->write == 0) abort
10760       81 7/subop/compare *ecx 0/imm32
10761       0f 84/jump-if-= $populate-mu-type:error1/disp32
10762 +--  6 lines: #?       # dump line ------------------------------------------------------------------------------------------------------------------------------------------------------
10768       (next-mu-token %ecx %edx)
10769       # if slice-empty?(word-slice) continue
10770       (slice-empty? %edx)  # => eax
10771       3d/compare-eax-and 0/imm32
10772       0f 85/jump-if-!= loop/disp32
10773       # if slice-equal?(word-slice, "}") break
10774       (slice-equal? %edx "}")
10775       3d/compare-eax-and 0/imm32
10776       0f 85/jump-if-!= break/disp32
10777 $populate-mu-type:parse-element:
10778       # v = parse-var-with-type(word-slice, first-line)
10779       # must do this first to strip the trailing ':' from word-slice before
10780       # using it in find-or-create-typeinfo-fields below
10781       # TODO: clean up that mutation in parse-var-with-type
10782       (parse-var-with-type %edx %ecx %esi *(ebp+0x10) *(ebp+0x14))
10783       # if v is an addr, abort
10784       (lookup *esi *(esi+4))  # => eax
10785       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
10786       (is-mu-addr-type? %eax)  # => eax
10787       3d/compare-eax-and 0/imm32/false
10788       0f 85/jump-if-!= $populate-mu-type:error2/disp32
10789       # if v is an array, abort  (we could support it, but initialization gets complex)
10790       (lookup *esi *(esi+4))  # => eax
10791       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
10792       (is-mu-array-type? %eax)  # => eax
10793       3d/compare-eax-and 0/imm32/false
10794       0f 85/jump-if-!= $populate-mu-type:error3/disp32
10795       # if v is a slice, abort
10796       (lookup *esi *(esi+4))  # => eax
10797       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
10798       (is-simple-mu-type? %eax 0xc)  # slice => eax
10799       3d/compare-eax-and 0/imm32/false
10800       0f 85/jump-if-!= $populate-mu-type:error4/disp32
10801       # if v is a stream, abort  (we could support it, but initialization gets even more complex)
10802       (lookup *esi *(esi+4))  # => eax
10803       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
10804       (is-mu-stream-type? %eax)  # => eax
10805       3d/compare-eax-and 0/imm32/false
10806       0f 85/jump-if-!= $populate-mu-type:error5/disp32
10807       # var tmp/ecx
10808       51/push-ecx
10809 $populate-mu-type:create-typeinfo-fields:
10810       # var r/ebx: (handle typeinfo-entry)
10811       (find-or-create-typeinfo-fields %edi %edx %ebx)
10812       # r->index = curr-index
10813       (lookup *ebx *(ebx+4))  # => eax
10814       8b/-> *(ebp-4) 1/r32/ecx
10815 #?       (write-buffered Stderr "saving index ")
10816 #?       (write-int32-hex-buffered Stderr %ecx)
10817 #?       (write-buffered Stderr " at ")
10818 #?       (write-int32-hex-buffered Stderr %edi)
10819 #?       (write-buffered Stderr Newline)
10820 #?       (flush Stderr)
10821       89/<- *(eax+8) 1/r32/ecx  # Typeinfo-entry-index
10822       # ++curr-index
10823       ff 0/subop/increment *(ebp-4)
10824 $populate-mu-type:set-input-type:
10825       # r->input-var = v
10826       8b/-> *esi 1/r32/ecx
10827       89/<- *eax 1/r32/ecx  # Typeinfo-entry-input-var
10828       8b/-> *(esi+4) 1/r32/ecx
10829       89/<- *(eax+4) 1/r32/ecx  # Typeinfo-entry-input-var
10830       # restore line
10831       59/pop-to-ecx
10832       {
10833 $populate-mu-type:create-output-type:
10834         # if (r->output-var == 0) create a new var with some placeholder data
10835         81 7/subop/compare *(eax+0xc) 0/imm32  # Typeinfo-entry-output-var
10836         75/jump-if-!= break/disp8
10837         8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
10838         (new-literal Heap %edx %eax)
10839       }
10840       e9/jump loop/disp32
10841     }
10842 $populate-mu-type:invalidate-total-size-in-bytes:
10843     # Offsets and total size may not be accurate here since we may not yet
10844     # have encountered the element types.
10845     # We'll recompute them separately after parsing the entire program.
10846     c7 0/subop/copy *(edi+0xc) -2/imm32/uninitialized  # Typeinfo-total-size-in-bytes
10847 $populate-mu-type:end:
10848     # . reclaim locals
10849     81 0/subop/add %esp 0x224/imm32
10850     # . restore registers
10851     5f/pop-to-edi
10852     5e/pop-to-esi
10853     5b/pop-to-ebx
10854     5a/pop-to-edx
10855     59/pop-to-ecx
10856     58/pop-to-eax
10857     # reclaim curr-index
10858     81 0/subop/add %esp 4/imm32
10859     # . epilogue
10860     89/<- %esp 5/r32/ebp
10861     5d/pop-to-ebp
10862     c3/return
10863 
10864 $populate-mu-type:error1:
10865     # error("incomplete type definition '" t->name "'\n")
10866     (write-buffered *(ebp+0x10) "incomplete type definition '")
10867     (type-name *edi)  # Typeinfo-id => eax
10868     (write-buffered *(ebp+0x10) %eax)
10869     (write-buffered *(ebp+0x10) "\n")
10870     (flush *(ebp+0x10))
10871     (stop *(ebp+0x14) 1)
10872     # never gets here
10873 
10874 $populate-mu-type:error2:
10875     (write-buffered *(ebp+0x10) "type ")
10876     (type-name *edi)  # Typeinfo-id => eax
10877     (write-buffered *(ebp+0x10) %eax)
10878     (write-buffered *(ebp+0x10) ": 'addr' elements not allowed\n")
10879     (flush *(ebp+0x10))
10880     (stop *(ebp+0x14) 1)
10881     # never gets here
10882 
10883 $populate-mu-type:error3:
10884     (write-buffered *(ebp+0x10) "type ")
10885     (type-name *edi)  # Typeinfo-id => eax
10886     (write-buffered *(ebp+0x10) %eax)
10887     (write-buffered *(ebp+0x10) ": 'array' elements not allowed for now\n")
10888     (flush *(ebp+0x10))
10889     (stop *(ebp+0x14) 1)
10890     # never gets here
10891 
10892 $populate-mu-type:error4:
10893     (write-buffered *(ebp+0x10) "type ")
10894     (type-name *edi)  # Typeinfo-id => eax
10895     (write-buffered *(ebp+0x10) %eax)
10896     (write-buffered *(ebp+0x10) ": 'slice' elements not allowed\n")
10897     (flush *(ebp+0x10))
10898     (stop *(ebp+0x14) 1)
10899     # never gets here
10900 
10901 $populate-mu-type:error5:
10902     (write-buffered *(ebp+0x10) "type ")
10903     (type-name *edi)  # Typeinfo-id => eax
10904     (write-buffered *(ebp+0x10) %eax)
10905     (write-buffered *(ebp+0x10) ": 'stream' elements not allowed for now\n")
10906     (flush *(ebp+0x10))
10907     (stop *(ebp+0x14) 1)
10908     # never gets here
10909 
10910 type-name:  # index: int -> result/eax: (addr array byte)
10911     # . prologue
10912     55/push-ebp
10913     89/<- %ebp 4/r32/esp
10914     #
10915     (index Type-id *(ebp+8))
10916 $type-name:end:
10917     # . epilogue
10918     89/<- %esp 5/r32/ebp
10919     5d/pop-to-ebp
10920     c3/return
10921 
10922 index:  # arr: (addr stream (handle array byte)), index: int -> result/eax: (addr array byte)
10923     # . prologue
10924     55/push-ebp
10925     89/<- %ebp 4/r32/esp
10926     # . save registers
10927     56/push-esi
10928     # TODO: bounds-check index
10929     # esi = arr
10930     8b/-> *(ebp+8) 6/r32/esi
10931     # eax = index
10932     8b/-> *(ebp+0xc) 0/r32/eax
10933     # eax = *(arr + 12 + index)
10934     8b/-> *(esi+eax<<2+0xc) 0/r32/eax
10935 $index:end:
10936     # . restore registers
10937     5e/pop-to-esi
10938     # . epilogue
10939     89/<- %esp 5/r32/ebp
10940     5d/pop-to-ebp
10941     c3/return
10942 
10943 #######################################################
10944 # Compute type sizes
10945 #######################################################
10946 
10947 # Compute the sizes of all user-defined types.
10948 # We'll need the sizes of their elements, which may be other user-defined
10949 # types, which we will compute as needed.
10950 
10951 # Initially, all user-defined types have their sizes set to -2 (invalid)
10952 populate-mu-type-sizes:  # err: (addr buffered-file), ed: (addr exit-descriptor)
10953     # . prologue
10954     55/push-ebp
10955     89/<- %ebp 4/r32/esp
10956 $populate-mu-type-sizes:total-sizes:
10957     # var curr/eax: (addr typeinfo) = lookup(Program->types)
10958     (lookup *_Program-types *_Program-types->payload)  # => eax
10959     {
10960       # if (curr == null) break
10961       3d/compare-eax-and 0/imm32/null
10962       74/jump-if-= break/disp8
10963       (populate-mu-type-sizes-in-type %eax *(ebp+8) *(ebp+0xc))
10964       # curr = lookup(curr->next)
10965       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
10966       eb/jump loop/disp8
10967     }
10968 $populate-mu-type-sizes:offsets:
10969     # curr = *Program->types
10970     (lookup *_Program-types *_Program-types->payload)  # => eax
10971     {
10972       # if (curr == null) break
10973       3d/compare-eax-and 0/imm32/null
10974       74/jump-if-= break/disp8
10975       (populate-mu-type-offsets %eax *(ebp+8) *(ebp+0xc))
10976       # curr = curr->next
10977       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
10978       eb/jump loop/disp8
10979     }
10980 $populate-mu-type-sizes:end:
10981     # . epilogue
10982     89/<- %esp 5/r32/ebp
10983     5d/pop-to-ebp
10984     c3/return
10985 
10986 # compute sizes of all fields, recursing as necessary
10987 # sum up all their sizes to arrive at total size
10988 # fields may be out of order, but that doesn't affect the answer
10989 populate-mu-type-sizes-in-type:  # T: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
10990     # . prologue
10991     55/push-ebp
10992     89/<- %ebp 4/r32/esp
10993     # . save registers
10994     50/push-eax
10995     51/push-ecx
10996     52/push-edx
10997     56/push-esi
10998     57/push-edi
10999     # esi = T
11000     8b/-> *(ebp+8) 6/r32/esi
11001     # if T is already computed, return
11002     81 7/subop/compare *(esi+0xc) 0/imm32  # Typeinfo-total-size-in-bytes
11003     0f 8d/jump-if->= $populate-mu-type-sizes-in-type:end/disp32
11004     # if T is being computed, abort
11005     81 7/subop/compare *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
11006     0f 84/jump-if-= $populate-mu-type-sizes-in-type:abort/disp32
11007     # tag T (-2 to -1) to avoid infinite recursion
11008     c7 0/subop/copy *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
11009     # var total-size/edi: int = 0
11010     bf/copy-to-edi 0/imm32
11011     # - for every field, if it's a user-defined type, compute its size
11012     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
11013     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
11014     89/<- %ecx 0/r32/eax
11015     # var table-size/edx: int = table->write
11016     8b/-> *ecx 2/r32/edx  # stream-write
11017     # var curr/ecx: (addr table_row) = table->data
11018     8d/copy-address *(ecx+0xc) 1/r32/ecx
11019     # var max/edx: (addr table_row) = table->data + table->write
11020     8d/copy-address *(ecx+edx) 2/r32/edx
11021     {
11022 $populate-mu-type-sizes-in-type:loop:
11023       # if (curr >= max) break
11024       39/compare %ecx 2/r32/edx
11025       73/jump-if-addr>= break/disp8
11026       # var t/eax: (addr typeinfo-entry) = lookup(curr->value)
11027       (lookup *(ecx+8) *(ecx+0xc))  # => eax
11028       # if (t->input-var == 0) silently ignore it; we'll emit a nice error message while type-checking
11029       81 7/subop/compare *eax 0/imm32  # Typeinfo-entry-input-var
11030       74/jump-if-= $populate-mu-type-sizes-in-type:end/disp8
11031       # compute size of t->input-var
11032       (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
11033       (compute-size-of-var %eax)  # => eax
11034       # result += eax
11035       01/add-to %edi 0/r32/eax
11036       # curr += row-size
11037       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
11038       #
11039       eb/jump loop/disp8
11040     }
11041     # - save result
11042     89/<- *(esi+0xc) 7/r32/edi  # Typeinfo-total-size-in-bytes
11043 $populate-mu-type-sizes-in-type:end:
11044     # . restore registers
11045     5f/pop-to-edi
11046     5e/pop-to-esi
11047     5a/pop-to-edx
11048     59/pop-to-ecx
11049     58/pop-to-eax
11050     # . epilogue
11051     89/<- %esp 5/r32/ebp
11052     5d/pop-to-ebp
11053     c3/return
11054 
11055 $populate-mu-type-sizes-in-type:abort:
11056     (write-buffered *(ebp+0xc) "cycle in type definitions\n")
11057     (flush *(ebp+0xc))
11058     (stop *(ebp+0x10) 1)
11059     # never gets here
11060 
11061 # Analogous to size-of, except we need to compute what size-of can just read
11062 # off the right data structures.
11063 compute-size-of-var:  # in: (addr var) -> result/eax: int
11064     # . prologue
11065     55/push-ebp
11066     89/<- %ebp 4/r32/esp
11067     # . push registers
11068     51/push-ecx
11069     # var t/ecx: (addr type-tree) = lookup(v->type)
11070     8b/-> *(ebp+8) 1/r32/ecx
11071     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
11072     89/<- %ecx 0/r32/eax
11073     # if (t->is-atom == false) t = lookup(t->left)
11074     {
11075       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
11076       75/jump-if-!= break/disp8
11077       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
11078       89/<- %ecx 0/r32/eax
11079     }
11080     # TODO: ensure t is an atom
11081     (compute-size-of-type-id *(ecx+4))  # Type-tree-value => eax
11082 $compute-size-of-var:end:
11083     # . restore registers
11084     59/pop-to-ecx
11085     # . epilogue
11086     89/<- %esp 5/r32/ebp
11087     5d/pop-to-ebp
11088     c3/return
11089 
11090 compute-size-of-type-id:  # t: type-id -> result/eax: int
11091     # . prologue
11092     55/push-ebp
11093     89/<- %ebp 4/r32/esp
11094     # . save registers
11095     51/push-ecx
11096     # var out/ecx: (handle typeinfo)
11097     68/push 0/imm32
11098     68/push 0/imm32
11099     89/<- %ecx 4/r32/esp
11100     # eax = t
11101     8b/-> *(ebp+8) 0/r32/eax
11102     # if t is a literal, return 0
11103     3d/compare-eax-and 0/imm32/literal
11104     0f 84/jump-if-= $compute-size-of-type-id:end/disp32  # eax changes type from type-id to int
11105     # if t is a byte, return 4 (because we don't really support non-multiples of 4)
11106     3d/compare-eax-and 8/imm32/byte
11107     {
11108       75/jump-if-!= break/disp8
11109       b8/copy-to-eax 4/imm32
11110       eb/jump $compute-size-of-type-id:end/disp8
11111     }
11112     # if t is a handle, return 8
11113     3d/compare-eax-and 4/imm32/handle
11114     {
11115       75/jump-if-!= break/disp8
11116       b8/copy-to-eax 8/imm32
11117       eb/jump $compute-size-of-type-id:end/disp8  # eax changes type from type-id to int
11118     }
11119     # if t is a slice, return 8
11120     3d/compare-eax-and 0xc/imm32/slice
11121     {
11122       75/jump-if-!= break/disp8
11123       b8/copy-to-eax 8/imm32
11124       eb/jump $compute-size-of-type-id:end/disp8  # eax changes type from type-id to int
11125     }
11126     # if t is a user-defined type, compute its size
11127     # TODO: support non-atom type
11128     (find-typeinfo %eax %ecx)
11129     {
11130       81 7/subop/compare *ecx 0/imm32
11131       74/jump-if-= break/disp8
11132 $compute-size-of-type-id:user-defined:
11133       (populate-mu-type-sizes %eax)
11134       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
11135       eb/jump $compute-size-of-type-id:end/disp8
11136     }
11137     # otherwise return the word size
11138     b8/copy-to-eax 4/imm32
11139 $compute-size-of-type-id:end:
11140     # . reclaim locals
11141     81 0/subop/add %esp 8/imm32
11142     # . restore registers
11143     59/pop-to-ecx
11144     # . epilogue
11145     89/<- %esp 5/r32/ebp
11146     5d/pop-to-ebp
11147     c3/return
11148 
11149 # at this point we have total sizes for all user-defined types
11150 # compute offsets for each element
11151 # complication: fields may be out of order
11152 populate-mu-type-offsets:  # in: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
11153     # . prologue
11154     55/push-ebp
11155     89/<- %ebp 4/r32/esp
11156     # . save registers
11157     50/push-eax
11158     51/push-ecx
11159     52/push-edx
11160     53/push-ebx
11161     56/push-esi
11162     57/push-edi
11163 #?     (dump-typeinfos "aaa\n")
11164     # var curr-offset/edi: int = 0
11165     bf/copy-to-edi 0/imm32
11166     # var table/ecx: (addr table string_key (handle typeinfo-entry)) = lookup(in->fields)
11167     8b/-> *(ebp+8) 1/r32/ecx
11168     (lookup *(ecx+4) *(ecx+8))  # Typeinfo-fields Typeinfo-fields => eax
11169     89/<- %ecx 0/r32/eax
11170     # var num-elems/edx: int = table->write / Typeinfo-fields-row-size
11171     8b/-> *ecx 2/r32/edx  # stream-write
11172     c1 5/subop/shift-right-logical  %edx 4/imm8
11173     # var i/ebx: int = 0
11174     bb/copy-to-ebx 0/imm32
11175     {
11176 $populate-mu-type-offsets:loop:
11177       39/compare %ebx 2/r32/edx
11178       0f 8d/jump-if->= break/disp32
11179 #?       (write-buffered Stderr "looking up index ")
11180 #?       (write-int32-hex-buffered Stderr %ebx)
11181 #?       (write-buffered Stderr " in ")
11182 #?       (write-int32-hex-buffered Stderr *(ebp+8))
11183 #?       (write-buffered Stderr Newline)
11184 #?       (flush Stderr)
11185       # var v/esi: (addr typeinfo-entry)
11186       (locate-typeinfo-entry-with-index %ecx %ebx *(ebp+0xc) *(ebp+0x10))  # => eax
11187       89/<- %esi 0/r32/eax
11188       # if v is null, silently move on; we'll emit a nice error message while type-checking
11189       81 7/subop/compare %esi 0/imm32  # Typeinfo-entry-input-var
11190       74/jump-if-= $populate-mu-type-offsets:end/disp8
11191       # if (v->input-var == 0) silently ignore v; we'll emit a nice error message while type-checking
11192       81 7/subop/compare *esi 0/imm32  # Typeinfo-entry-input-var
11193       74/jump-if-= $populate-mu-type-offsets:end/disp8
11194       # v->output-var->offset = curr-offset
11195       # . eax: (addr var)
11196       (lookup *(esi+0xc) *(esi+0x10))  # Typeinfo-entry-output-var Typeinfo-entry-output-var => eax
11197       89/<- *(eax+0x14) 7/r32/edi  # Var-offset
11198       # curr-offset += size-of(v->input-var)
11199       (lookup *esi *(esi+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
11200       (size-of %eax)  # => eax
11201       01/add-to %edi 0/r32/eax
11202       # ++i
11203       43/increment-ebx
11204       e9/jump loop/disp32
11205     }
11206 $populate-mu-type-offsets:end:
11207     # . restore registers
11208     5f/pop-to-edi
11209     5e/pop-to-esi
11210     5b/pop-to-ebx
11211     5a/pop-to-edx
11212     59/pop-to-ecx
11213     58/pop-to-eax
11214     # . epilogue
11215     89/<- %esp 5/r32/ebp
11216     5d/pop-to-ebp
11217     c3/return
11218 
11219 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)
11220     # . prologue
11221     55/push-ebp
11222     89/<- %ebp 4/r32/esp
11223     # . save registers
11224     51/push-ecx
11225     52/push-edx
11226     53/push-ebx
11227     56/push-esi
11228     57/push-edi
11229     # esi = table
11230     8b/-> *(ebp+8) 6/r32/esi
11231     # var curr/ecx: (addr row (handle array byte) (handle typeinfo-entry)) = table->data
11232     8d/copy-address *(esi+0xc) 1/r32/ecx
11233     # var max/edx: (addr byte) = &table->data[table->write]
11234     8b/-> *esi 2/r32/edx
11235     8d/copy-address *(ecx+edx) 2/r32/edx
11236     {
11237 $locate-typeinfo-entry-with-index:loop:
11238       39/compare %ecx 2/r32/edx
11239       73/jump-if-addr>= break/disp8
11240       # var v/eax: (addr typeinfo-entry)
11241       (lookup *(ecx+8) *(ecx+0xc))  # => eax
11242       # if (v->index == idx) return v
11243       8b/-> *(eax+8) 3/r32/ebx  # Typeinfo-entry-index
11244 #?       (write-buffered Stderr "comparing ")
11245 #?       (write-int32-hex-buffered Stderr %ebx)
11246 #?       (write-buffered Stderr " and ")
11247 #?       (write-int32-hex-buffered Stderr *(ebp+0xc))
11248 #?       (write-buffered Stderr Newline)
11249 #?       (flush Stderr)
11250       39/compare *(ebp+0xc) 3/r32/ebx
11251       74/jump-if-= $locate-typeinfo-entry-with-index:end/disp8
11252       # curr += Typeinfo-entry-size
11253       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-entry-size
11254       #
11255       eb/jump loop/disp8
11256     }
11257     # return 0
11258     b8/copy-to-eax 0/imm32
11259 $locate-typeinfo-entry-with-index:end:
11260 #?     (write-buffered Stderr "returning ")
11261 #?     (write-int32-hex-buffered Stderr %eax)
11262 #?     (write-buffered Stderr Newline)
11263 #?     (flush Stderr)
11264     # . restore registers
11265     5f/pop-to-edi
11266     5e/pop-to-esi
11267     5b/pop-to-ebx
11268     5a/pop-to-edx
11269     59/pop-to-ecx
11270     # . epilogue
11271     89/<- %esp 5/r32/ebp
11272     5d/pop-to-ebp
11273     c3/return
11274 
11275 dump-typeinfos:  # hdr: (addr array byte)
11276     # . prologue
11277     55/push-ebp
11278     89/<- %ebp 4/r32/esp
11279     # . save registers
11280     50/push-eax
11281     #
11282     (write-buffered Stderr *(ebp+8))
11283     (flush Stderr)
11284     # var curr/eax: (addr typeinfo) = lookup(Program->types)
11285     (lookup *_Program-types *_Program-types->payload)  # => eax
11286     {
11287       # if (curr == null) break
11288       3d/compare-eax-and 0/imm32
11289       74/jump-if-= break/disp8
11290       (write-buffered Stderr "---\n")
11291       (flush Stderr)
11292       (dump-typeinfo %eax)
11293       # curr = lookup(curr->next)
11294       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
11295       eb/jump loop/disp8
11296     }
11297 $dump-typeinfos:end:
11298     # . restore registers
11299     58/pop-to-eax
11300     # . epilogue
11301     89/<- %esp 5/r32/ebp
11302     5d/pop-to-ebp
11303     c3/return
11304 
11305 dump-typeinfo:  # in: (addr typeinfo)
11306     # . prologue
11307     55/push-ebp
11308     89/<- %ebp 4/r32/esp
11309     # . save registers
11310     50/push-eax
11311     51/push-ecx
11312     52/push-edx
11313     53/push-ebx
11314     56/push-esi
11315     57/push-edi
11316     # esi = in
11317     8b/-> *(ebp+8) 6/r32/esi
11318     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
11319     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
11320     89/<- %ecx 0/r32/eax
11321     (write-buffered Stderr "id:")
11322     (write-int32-hex-buffered Stderr *esi)
11323     (write-buffered Stderr "\n")
11324     (write-buffered Stderr "fields @ ")
11325     (write-int32-hex-buffered Stderr %ecx)
11326     (write-buffered Stderr Newline)
11327     (flush Stderr)
11328     (write-buffered Stderr "  write: ")
11329     (write-int32-hex-buffered Stderr *ecx)
11330     (write-buffered Stderr Newline)
11331     (flush Stderr)
11332     (write-buffered Stderr "  read: ")
11333     (write-int32-hex-buffered Stderr *(ecx+4))
11334     (write-buffered Stderr Newline)
11335     (flush Stderr)
11336     (write-buffered Stderr "  size: ")
11337     (write-int32-hex-buffered Stderr *(ecx+8))
11338     (write-buffered Stderr Newline)
11339     (flush Stderr)
11340     # var table-size/edx: int = table->write
11341     8b/-> *ecx 2/r32/edx  # stream-write
11342     # var curr/ecx: (addr table_row) = table->data
11343     8d/copy-address *(ecx+0xc) 1/r32/ecx
11344     # var max/edx: (addr table_row) = table->data + table->write
11345     8d/copy-address *(ecx+edx) 2/r32/edx
11346     {
11347 $dump-typeinfo:loop:
11348       # if (curr >= max) break
11349       39/compare %ecx 2/r32/edx
11350       0f 83/jump-if-addr>= break/disp32
11351       (write-buffered Stderr "  row:\n")
11352       (write-buffered Stderr "    key: ")
11353       (write-int32-hex-buffered Stderr *ecx)
11354       (write-buffered Stderr ",")
11355       (write-int32-hex-buffered Stderr *(ecx+4))
11356       (write-buffered Stderr " = '")
11357       (lookup *ecx *(ecx+4))
11358       (write-buffered Stderr %eax)
11359       (write-buffered Stderr "' @ ")
11360       (write-int32-hex-buffered Stderr %eax)
11361       (write-buffered Stderr Newline)
11362       (flush Stderr)
11363       (write-buffered Stderr "    value: ")
11364       (write-int32-hex-buffered Stderr *(ecx+8))
11365       (write-buffered Stderr ",")
11366       (write-int32-hex-buffered Stderr *(ecx+0xc))
11367       (write-buffered Stderr " = typeinfo-entry@")
11368       (lookup *(ecx+8) *(ecx+0xc))
11369       (write-int32-hex-buffered Stderr %eax)
11370       (write-buffered Stderr Newline)
11371       (flush Stderr)
11372       (write-buffered Stderr "        input var@")
11373       (dump-var 5 %eax)
11374       (lookup *(ecx+8) *(ecx+0xc))
11375       (write-buffered Stderr "        index: ")
11376       (write-int32-hex-buffered Stderr *(eax+8))
11377       (write-buffered Stderr Newline)
11378       (flush Stderr)
11379       (write-buffered Stderr "        output var@")
11380       8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
11381       (dump-var 5 %eax)
11382       (flush Stderr)
11383       # curr += row-size
11384       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
11385       #
11386       e9/jump loop/disp32
11387     }
11388 $dump-typeinfo:end:
11389     # . restore registers
11390     5f/pop-to-edi
11391     5e/pop-to-esi
11392     5b/pop-to-ebx
11393     5a/pop-to-edx
11394     59/pop-to-ecx
11395     58/pop-to-eax
11396     # . epilogue
11397     89/<- %esp 5/r32/ebp
11398     5d/pop-to-ebp
11399     c3/return
11400 
11401 dump-var:  # indent: int, v: (addr handle var)
11402     # . prologue
11403     55/push-ebp
11404     89/<- %ebp 4/r32/esp
11405     # . save registers
11406     50/push-eax
11407     53/push-ebx
11408     # eax = v
11409     8b/-> *(ebp+0xc) 0/r32/eax
11410     #
11411     (write-int32-hex-buffered Stderr *eax)
11412     (write-buffered Stderr ",")
11413     (write-int32-hex-buffered Stderr *(eax+4))
11414     (write-buffered Stderr "->")
11415     (lookup *eax *(eax+4))
11416     (write-int32-hex-buffered Stderr %eax)
11417     (write-buffered Stderr Newline)
11418     (flush Stderr)
11419     {
11420       3d/compare-eax-and 0/imm32
11421       0f 84/jump-if-= break/disp32
11422       (emit-indent Stderr *(ebp+8))
11423       (write-buffered Stderr "name: ")
11424       89/<- %ebx 0/r32/eax
11425       (write-int32-hex-buffered Stderr *ebx)  # Var-name
11426       (write-buffered Stderr ",")
11427       (write-int32-hex-buffered Stderr *(ebx+4))  # Var-name
11428       (write-buffered Stderr "->")
11429       (lookup *ebx *(ebx+4))  # Var-name
11430       (write-int32-hex-buffered Stderr %eax)
11431       {
11432         3d/compare-eax-and 0/imm32
11433         74/jump-if-= break/disp8
11434         (write-buffered Stderr Space)
11435         (write-buffered Stderr %eax)
11436       }
11437       (write-buffered Stderr Newline)
11438       (flush Stderr)
11439       (emit-indent Stderr *(ebp+8))
11440       (write-buffered Stderr "block depth: ")
11441       (write-int32-hex-buffered Stderr *(ebx+0x10))  # Var-block-depth
11442       (write-buffered Stderr Newline)
11443       (flush Stderr)
11444       (emit-indent Stderr *(ebp+8))
11445       (write-buffered Stderr "stack offset: ")
11446       (write-int32-hex-buffered Stderr *(ebx+0x14))  # Var-offset
11447       (write-buffered Stderr Newline)
11448       (flush Stderr)
11449       (emit-indent Stderr *(ebp+8))
11450       (write-buffered Stderr "reg: ")
11451       (write-int32-hex-buffered Stderr *(ebx+0x18))  # Var-register
11452       (write-buffered Stderr ",")
11453       (write-int32-hex-buffered Stderr *(ebx+0x1c))  # Var-register
11454       (write-buffered Stderr "->")
11455       (flush Stderr)
11456       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register
11457       (write-int32-hex-buffered Stderr %eax)
11458       {
11459         3d/compare-eax-and 0/imm32
11460         74/jump-if-= break/disp8
11461         (write-buffered Stderr Space)
11462         (write-buffered Stderr %eax)
11463       }
11464       (write-buffered Stderr Newline)
11465       (flush Stderr)
11466     }
11467 $dump-var:end:
11468     # . restore registers
11469     5b/pop-to-ebx
11470     58/pop-to-eax
11471     # . epilogue
11472     89/<- %esp 5/r32/ebp
11473     5d/pop-to-ebp
11474     c3/return
11475 
11476 #######################################################
11477 # Type-checking
11478 #######################################################
11479 
11480 check-mu-types:  # err: (addr buffered-file), ed: (addr exit-descriptor)
11481     # . prologue
11482     55/push-ebp
11483     89/<- %ebp 4/r32/esp
11484     # . save registers
11485     50/push-eax
11486     # var curr/eax: (addr function) = lookup(Program->functions)
11487     (lookup *_Program-functions *_Program-functions->payload)  # => eax
11488     {
11489 $check-mu-types:loop:
11490       # if (curr == null) break
11491       3d/compare-eax-and 0/imm32
11492       0f 84/jump-if-= break/disp32
11493 +--  8 lines: #?       # dump curr->name ------------------------------------------------------------------------------------------------------------------------------------------------
11501       (check-mu-function %eax *(ebp+8) *(ebp+0xc))
11502       # curr = lookup(curr->next)
11503       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
11504       e9/jump loop/disp32
11505     }
11506 $check-mu-types:end:
11507     # . restore registers
11508     58/pop-to-eax
11509     # . epilogue
11510     89/<- %esp 5/r32/ebp
11511     5d/pop-to-ebp
11512     c3/return
11513 
11514 check-mu-function:  # fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11515     # . prologue
11516     55/push-ebp
11517     89/<- %ebp 4/r32/esp
11518     # . save registers
11519     50/push-eax
11520     # eax = f
11521     8b/-> *(ebp+8) 0/r32/eax
11522     # TODO: anything to check in header?
11523     # var body/eax: (addr block) = lookup(f->body)
11524     (lookup *(eax+0x18) *(eax+0x1c))  # Function-body Function-body => eax
11525     (check-mu-block %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10))
11526 $check-mu-function:end:
11527     # . restore registers
11528     58/pop-to-eax
11529     # . epilogue
11530     89/<- %esp 5/r32/ebp
11531     5d/pop-to-ebp
11532     c3/return
11533 
11534 check-mu-block:  # block: (addr block), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11535     # . prologue
11536     55/push-ebp
11537     89/<- %ebp 4/r32/esp
11538     # . save registers
11539     50/push-eax
11540     # eax = block
11541     8b/-> *(ebp+8) 0/r32/eax
11542     # var stmts/eax: (addr list stmt) = lookup(block->statements)
11543     (lookup *(eax+4) *(eax+8))  # Block-stmts Block-stmts => eax
11544     #
11545     {
11546 $check-mu-block:check-empty:
11547       3d/compare-eax-and 0/imm32
11548       0f 84/jump-if-= break/disp32
11549       # emit block->statements
11550       (check-mu-stmt-list %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11551     }
11552 $check-mu-block:end:
11553     # . restore registers
11554     58/pop-to-eax
11555     # . epilogue
11556     89/<- %esp 5/r32/ebp
11557     5d/pop-to-ebp
11558     c3/return
11559 
11560 check-mu-stmt-list:  # stmts: (addr list stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11561     # . prologue
11562     55/push-ebp
11563     89/<- %ebp 4/r32/esp
11564     # . save registers
11565     50/push-eax
11566     56/push-esi
11567     # esi = stmts
11568     8b/-> *(ebp+8) 6/r32/esi
11569     {
11570 $check-mu-stmt-list:loop:
11571       81 7/subop/compare %esi 0/imm32
11572       0f 84/jump-if-= break/disp32
11573       # var curr-stmt/eax: (addr stmt) = lookup(stmts->value)
11574       (lookup *esi *(esi+4))  # List-value List-value => eax
11575       {
11576 $check-mu-stmt-list:check-for-block:
11577         81 7/subop/compare *eax 0/imm32/block  # Stmt-tag
11578         75/jump-if-!= break/disp8
11579 $check-mu-stmt-list:block:
11580         (check-mu-block %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11581         eb/jump $check-mu-stmt-list:continue/disp8
11582       }
11583       {
11584 $check-mu-stmt-list:check-for-stmt1:
11585         81 7/subop/compare *eax 1/imm32/stmt1  # Stmt-tag
11586         0f 85/jump-if-!= break/disp32
11587 $check-mu-stmt-list:stmt1:
11588         (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11589         eb/jump $check-mu-stmt-list:continue/disp8
11590       }
11591       {
11592 $check-mu-stmt-list:check-for-reg-var-def:
11593         81 7/subop/compare *eax 3/imm32/reg-var-def  # Stmt-tag
11594         0f 85/jump-if-!= break/disp32
11595 $check-mu-stmt-list:reg-var-def:
11596         (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11597         eb/jump $check-mu-stmt-list:continue/disp8
11598       }
11599 $check-mu-stmt-list:continue:
11600       # TODO: raise an error on unrecognized Stmt-tag
11601       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
11602       89/<- %esi 0/r32/eax
11603       e9/jump loop/disp32
11604     }
11605 $check-mu-stmt-list:end:
11606     # . restore registers
11607     5e/pop-to-esi
11608     58/pop-to-eax
11609     # . epilogue
11610     89/<- %esp 5/r32/ebp
11611     5d/pop-to-ebp
11612     c3/return
11613 
11614 check-mu-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11615     # . prologue
11616     55/push-ebp
11617     89/<- %ebp 4/r32/esp
11618     # . save registers
11619     50/push-eax
11620     # - if stmt's operation matches a primitive, check against it
11621     (has-primitive-name? *(ebp+8))  # => eax
11622     3d/compare-eax-and 0/imm32/false
11623     {
11624       74/jump-if-= break/disp8
11625       (check-mu-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11626       e9/jump $check-mu-stmt:end/disp32
11627     }
11628     # - otherwise find a function to check against
11629     # var f/eax: (addr function) = lookup(*Program->functions)
11630     (lookup *_Program-functions *_Program-functions->payload)  # => eax
11631     (find-matching-function %eax *(ebp+8))  # => eax
11632     3d/compare-eax-and 0/imm32
11633     {
11634       74/jump-if-= break/disp8
11635       (check-mu-call *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11636       eb/jump $check-mu-stmt:end/disp8
11637     }
11638     # var f/eax: (addr function) = lookup(*Program->signatures)
11639     (lookup *_Program-signatures *_Program-signatures->payload)  # => eax
11640     (find-matching-function %eax *(ebp+8))  # => eax
11641     3d/compare-eax-and 0/imm32
11642     {
11643       74/jump-if-= break/disp8
11644       (check-mu-call *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11645       eb/jump $check-mu-stmt:end/disp8
11646     }
11647     # - otherwise abort
11648     e9/jump $check-mu-stmt:unknown-call/disp32
11649 $check-mu-stmt:end:
11650     # . restore registers
11651     58/pop-to-eax
11652     # . epilogue
11653     89/<- %esp 5/r32/ebp
11654     5d/pop-to-ebp
11655     c3/return
11656 
11657 $check-mu-stmt:unknown-call:
11658     (write-buffered *(ebp+0x10) "unknown function '")
11659     8b/-> *(ebp+8) 0/r32/eax
11660     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
11661     (write-buffered *(ebp+0x10) %eax)
11662     (write-buffered *(ebp+0x10) "'\n")
11663     (flush *(ebp+0x10))
11664     (stop *(ebp+0x14) 1)
11665     # never gets here
11666 
11667 has-primitive-name?:  # stmt: (addr stmt) -> result/eax: boolean
11668     # . prologue
11669     55/push-ebp
11670     89/<- %ebp 4/r32/esp
11671     # . save registers
11672     51/push-ecx
11673     56/push-esi
11674     # var name/esi: (addr array byte) = lookup(stmt->operation)
11675     8b/-> *(ebp+8) 6/r32/esi
11676     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
11677     89/<- %esi 0/r32/eax
11678     # if (name == "get") return true
11679     (string-equal? %esi "get")  # => eax
11680     3d/compare-eax-and 0/imm32/false
11681     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11682     # if (name == "index") return true
11683     (string-equal? %esi "index")  # => eax
11684     3d/compare-eax-and 0/imm32/false
11685     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11686     # if (name == "length") return true
11687     (string-equal? %esi "length")  # => eax
11688     3d/compare-eax-and 0/imm32/false
11689     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11690     # if (name == "compute-offset") return true
11691     (string-equal? %esi "compute-offset")  # => eax
11692     3d/compare-eax-and 0/imm32/false
11693     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11694     # if (name == "allocate") return true
11695     (string-equal? %esi "allocate")  # => eax
11696     3d/compare-eax-and 0/imm32/false
11697     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11698     # if (name == "populate") return true
11699     (string-equal? %esi "populate")  # => eax
11700     3d/compare-eax-and 0/imm32/false
11701     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11702     # if (name == "populate-stream") return true
11703     (string-equal? %esi "populate-stream")  # => eax
11704     3d/compare-eax-and 0/imm32/false
11705     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11706     # if (name == "read-from-stream") return true
11707     (string-equal? %esi "read-from-stream")  # => eax
11708     3d/compare-eax-and 0/imm32/false
11709     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11710     # if (name == "write-to-stream") return true
11711     (string-equal? %esi "write-to-stream")  # => eax
11712     3d/compare-eax-and 0/imm32/false
11713     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11714     # var curr/ecx: (addr primitive) = Primitives
11715     b9/copy-to-ecx Primitives/imm32
11716     {
11717 $has-primitive-name?:loop:
11718       # if (curr == null) break
11719       81 7/subop/compare %ecx 0/imm32
11720       74/jump-if-= break/disp8
11721       # if (primitive->name == name) return true
11722       (lookup *ecx *(ecx+4))  # Primitive-name Primitive-name => eax
11723       (string-equal? %esi %eax)  # => eax
11724       3d/compare-eax-and 0/imm32/false
11725       75/jump-if-!= $has-primitive-name?:end/disp8
11726 $has-primitive-name?:next-primitive:
11727       # curr = curr->next
11728       (lookup *(ecx+0x38) *(ecx+0x3c))  # Primitive-next Primitive-next => eax
11729       89/<- %ecx 0/r32/eax
11730       #
11731       e9/jump loop/disp32
11732     }
11733     # return null
11734     b8/copy-to-eax 0/imm32
11735 $has-primitive-name?:end:
11736     # . restore registers
11737     5e/pop-to-esi
11738     59/pop-to-ecx
11739     # . epilogue
11740     89/<- %esp 5/r32/ebp
11741     5d/pop-to-ebp
11742     c3/return
11743 
11744 check-mu-primitive:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11745     # . prologue
11746     55/push-ebp
11747     89/<- %ebp 4/r32/esp
11748     # . save registers
11749     50/push-eax
11750     51/push-ecx
11751     # var op/ecx: (addr array byte) = lookup(stmt->operation)
11752     8b/-> *(ebp+8) 0/r32/eax
11753     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
11754     89/<- %ecx 0/r32/eax
11755     # if (op == "copy") check-mu-copy-stmt
11756     {
11757       (string-equal? %ecx "copy")  # => eax
11758       3d/compare-eax-and 0/imm32/false
11759       74/jump-if-= break/disp8
11760       (check-mu-copy-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11761       e9/jump $check-mu-primitive:end/disp32
11762     }
11763     # if (op == "copy-to") check-mu-copy-to-stmt
11764     {
11765       (string-equal? %ecx "copy-to")  # => eax
11766       3d/compare-eax-and 0/imm32/false
11767       74/jump-if-= break/disp8
11768       (check-mu-copy-to-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11769       e9/jump $check-mu-primitive:end/disp32
11770     }
11771     # if (op == "compare") check-mu-compare-stmt
11772     {
11773       (string-equal? %ecx "compare")  # => eax
11774       3d/compare-eax-and 0/imm32/false
11775       74/jump-if-= break/disp8
11776       (check-mu-compare-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11777       e9/jump $check-mu-primitive:end/disp32
11778     }
11779     # if (op == "address") check-mu-address-stmt
11780     {
11781       (string-equal? %ecx "address")  # => eax
11782       3d/compare-eax-and 0/imm32/false
11783       74/jump-if-= break/disp8
11784       (check-mu-address-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11785       e9/jump $check-mu-primitive:end/disp32
11786     }
11787     # if (op == "get") check-mu-get-stmt
11788     {
11789       (string-equal? %ecx "get")  # => eax
11790       3d/compare-eax-and 0/imm32/false
11791       74/jump-if-= break/disp8
11792       (check-mu-get-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11793       e9/jump $check-mu-primitive:end/disp32
11794     }
11795     # if (op == "index") check-mu-index-stmt
11796     {
11797       (string-equal? %ecx "index")  # => eax
11798       3d/compare-eax-and 0/imm32/false
11799       74/jump-if-= break/disp8
11800       (check-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11801       e9/jump $check-mu-primitive:end/disp32
11802     }
11803     # if (op == "length") check-mu-length-stmt
11804     {
11805       (string-equal? %ecx "length")  # => eax
11806       3d/compare-eax-and 0/imm32/false
11807       74/jump-if-= break/disp8
11808       (check-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11809       e9/jump $check-mu-primitive:end/disp32
11810     }
11811     # if (op == "compute-offset") check-mu-compute-offset-stmt
11812     {
11813       (string-equal? %ecx "compute-offset")  # => eax
11814       3d/compare-eax-and 0/imm32/false
11815       74/jump-if-= break/disp8
11816       (check-mu-compute-offset-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11817       e9/jump $check-mu-primitive:end/disp32
11818     }
11819     # if (op == "allocate") check-mu-allocate-stmt
11820     {
11821       (string-equal? %ecx "allocate")  # => eax
11822       3d/compare-eax-and 0/imm32/false
11823       74/jump-if-= break/disp8
11824       (check-mu-allocate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11825       e9/jump $check-mu-primitive:end/disp32
11826     }
11827     # if (op == "populate") check-mu-populate-stmt
11828     {
11829       (string-equal? %ecx "populate")  # => eax
11830       3d/compare-eax-and 0/imm32/false
11831       74/jump-if-= break/disp8
11832       (check-mu-populate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11833       e9/jump $check-mu-primitive:end/disp32
11834     }
11835     # if (op == "populate-stream") check-mu-populate-stream-stmt
11836     {
11837       (string-equal? %ecx "populate-stream")  # => eax
11838       3d/compare-eax-and 0/imm32/false
11839       74/jump-if-= break/disp8
11840       (check-mu-populate-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11841       e9/jump $check-mu-primitive:end/disp32
11842     }
11843     # if (op == "read-from-stream") check-mu-read-from-stream-stmt
11844     {
11845       (string-equal? %ecx "read-from-stream")  # => eax
11846       3d/compare-eax-and 0/imm32/false
11847       74/jump-if-= break/disp8
11848       (check-mu-read-from-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11849       e9/jump $check-mu-primitive:end/disp32
11850     }
11851     # if (op == "write-to-stream") check-mu-write-to-stream-stmt
11852     {
11853       (string-equal? %ecx "write-to-stream")  # => eax
11854       3d/compare-eax-and 0/imm32/false
11855       74/jump-if-= break/disp8
11856       (check-mu-write-to-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11857       e9/jump $check-mu-primitive:end/disp32
11858     }
11859     # otherwise check-numberlike-stmt
11860     (check-mu-numberlike-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11861 $check-mu-primitive:end:
11862     # . restore registers
11863     59/pop-to-ecx
11864     58/pop-to-eax
11865     # . epilogue
11866     89/<- %esp 5/r32/ebp
11867     5d/pop-to-ebp
11868     c3/return
11869 
11870 # by default, Mu primitives should only operate on 'number-like' types
11871 check-mu-numberlike-primitive:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11872     # . prologue
11873     55/push-ebp
11874     89/<- %ebp 4/r32/esp
11875     # . save registers
11876     50/push-eax
11877     51/push-ecx
11878     56/push-esi
11879     # esi = stmt
11880     8b/-> *(ebp+8) 6/r32/esi
11881     # var gas/ecx: int = 2
11882     b9/copy-to-ecx 2/imm32
11883     # - check at most 1 output
11884     # var output/eax: (addr stmt-var) = stmt->outputs
11885     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
11886     {
11887       3d/compare-eax-and 0/imm32
11888       74/jump-if-= break/disp8
11889 $check-mu-numberlike-primitive:output:
11890       (check-mu-numberlike-output %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11891       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
11892       3d/compare-eax-and 0/imm32
11893       0f 85/jump-if-!= $check-mu-numberlike-primitive:error-too-many-outputs/disp32
11894       # check output is in a register
11895       # --gas
11896       49/decrement-ecx
11897     }
11898     # - check first inout
11899     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11900     {
11901       3d/compare-eax-and 0/imm32
11902       0f 84/jump-if-= $check-mu-numberlike-primitive:end/disp32
11903 $check-mu-numberlike-primitive:first-inout:
11904       (check-mu-numberlike-arg %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11905       # --gas
11906       49/decrement-ecx
11907     }
11908     # - check second inout
11909     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
11910     {
11911       3d/compare-eax-and 0/imm32
11912       74/jump-if-= $check-mu-numberlike-primitive:end/disp8
11913 $check-mu-numberlike-primitive:second-inout:
11914       # is a second inout allowed?
11915       81 7/subop/compare %ecx 0/imm32
11916       0f 84/jump-if-= $check-mu-numberlike-primitive:error-too-many-inouts/disp32
11917 $check-mu-numberlike-primitive:second-inout-permitted:
11918       (check-mu-numberlike-arg %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11919     }
11920 $check-mu-numberlike-primitive:third-inout:
11921     # if there's a third arg, raise an error
11922     81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
11923     0f 85/jump-if-!= $check-mu-numberlike-primitive:error-too-many-inouts/disp32
11924 $check-mu-numberlike-primitive:end:
11925     # . restore registers
11926     5e/pop-to-esi
11927     59/pop-to-ecx
11928     58/pop-to-eax
11929     # . epilogue
11930     89/<- %esp 5/r32/ebp
11931     5d/pop-to-ebp
11932     c3/return
11933 
11934 $check-mu-numberlike-primitive:error-too-many-inouts:
11935     (write-buffered *(ebp+0x10) "fn ")
11936     8b/-> *(ebp+0xc) 0/r32/eax
11937     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11938     (write-buffered *(ebp+0x10) %eax)
11939     (write-buffered *(ebp+0x10) ": stmt ")
11940     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
11941     (write-buffered *(ebp+0x10) %eax)
11942     (write-buffered *(ebp+0x10) ": too many inouts; most primitives support at most two arguments, across inouts and outputs\n")
11943     (flush *(ebp+0x10))
11944     (stop *(ebp+0x14) 1)
11945     # never gets here
11946 
11947 $check-mu-numberlike-primitive:error-too-many-outputs:
11948     (write-buffered *(ebp+0x10) "fn ")
11949     8b/-> *(ebp+0xc) 0/r32/eax
11950     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11951     (write-buffered *(ebp+0x10) %eax)
11952     (write-buffered *(ebp+0x10) ": stmt ")
11953     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
11954     (write-buffered *(ebp+0x10) %eax)
11955     (write-buffered *(ebp+0x10) ": too many outputs; most primitives support at most one output\n")
11956     (flush *(ebp+0x10))
11957     (stop *(ebp+0x14) 1)
11958     # never gets here
11959 
11960 check-mu-numberlike-arg:  # v: (addr stmt-var), stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11961     # . prologue
11962     55/push-ebp
11963     89/<- %ebp 4/r32/esp
11964     # . save registers
11965     50/push-eax
11966     56/push-esi
11967     # var t/esi: (addr type-tree) = lookup(v->value->type)
11968     8b/-> *(ebp+8) 0/r32/eax
11969     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11970     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11971     89/<- %esi 0/r32/eax
11972 $check-mu-numberlike-arg:check-literal:
11973     # if t is an int, return
11974     (is-simple-mu-type? %esi 0)  # literal => eax
11975     3d/compare-eax-and 0/imm32/false
11976     75/jump-if-!= $check-mu-numberlike-arg:end/disp8
11977 $check-mu-numberlike-arg:check-addr:
11978     # if t is an addr and v is dereferenced, return
11979     {
11980       (is-mu-addr-type? %esi)  # => eax
11981       3d/compare-eax-and 0/imm32/false
11982       74/jump-if-= break/disp8
11983       8b/-> *(ebp+8) 0/r32/eax
11984       8b/-> *(eax+0x10) 0/r32/eax
11985       3d/compare-eax-and 0/imm32/false
11986       75/jump-if-!= $check-mu-numberlike-arg:end/disp8
11987     }
11988 $check-mu-numberlike-arg:output-checks:
11989     (check-mu-numberlike-output *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18))
11990 $check-mu-numberlike-arg:end:
11991     # . restore registers
11992     5e/pop-to-esi
11993     58/pop-to-eax
11994     # . epilogue
11995     89/<- %esp 5/r32/ebp
11996     5d/pop-to-ebp
11997     c3/return
11998 
11999 check-mu-numberlike-output:  # v: (addr stmt-var), stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12000     # . prologue
12001     55/push-ebp
12002     89/<- %ebp 4/r32/esp
12003     # . save registers
12004     50/push-eax
12005     56/push-esi
12006     # var t/esi: (addr type-tree) = lookup(v->value->type)
12007     8b/-> *(ebp+8) 0/r32/eax
12008     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12009     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12010     89/<- %esi 0/r32/eax
12011 $check-mu-numberlike-output:check-int:
12012     # if t is an int, return
12013     (is-simple-mu-type? %esi 1)  # int => eax
12014     3d/compare-eax-and 0/imm32/false
12015     75/jump-if-!= $check-mu-numberlike-output:end/disp8
12016 $check-mu-numberlike-output:check-boolean:
12017     # if t is a boolean, return
12018     (is-simple-mu-type? %esi 5)  # boolean => eax
12019     3d/compare-eax-and 0/imm32/false
12020     75/jump-if-!= $check-mu-numberlike-output:end/disp8
12021 $check-mu-numberlike-output:check-byte:
12022     # if t is a byte, return
12023     (is-simple-mu-type? %esi 8)  # byte => eax
12024     3d/compare-eax-and 0/imm32/false
12025     75/jump-if-!= $check-mu-numberlike-output:end/disp8
12026     e9/jump $check-mu-numberlike-output:fail/disp32
12027 $check-mu-numberlike-output:end:
12028     # . restore registers
12029     5e/pop-to-esi
12030     58/pop-to-eax
12031     # . epilogue
12032     89/<- %esp 5/r32/ebp
12033     5d/pop-to-ebp
12034     c3/return
12035 
12036 $check-mu-numberlike-output:fail:
12037     # otherwise raise an error
12038     (write-buffered *(ebp+0x14) "fn ")
12039     8b/-> *(ebp+0x10) 0/r32/eax
12040     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12041     (write-buffered *(ebp+0x14) %eax)
12042     (write-buffered *(ebp+0x14) ": stmt ")
12043     8b/-> *(ebp+0xc) 0/r32/eax
12044     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
12045     (write-buffered *(ebp+0x14) %eax)
12046     (write-buffered *(ebp+0x14) ": only non-addr scalar args permitted\n")
12047     (flush *(ebp+0x14))
12048     (stop *(ebp+0x18) 1)
12049     # never gets here
12050 
12051 check-mu-copy-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12052     # . prologue
12053     55/push-ebp
12054     89/<- %ebp 4/r32/esp
12055     # . save registers
12056 $check-mu-copy-stmt:end:
12057     # . restore registers
12058     # . epilogue
12059     89/<- %esp 5/r32/ebp
12060     5d/pop-to-ebp
12061     c3/return
12062 
12063 check-mu-copy-to-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12064     # . prologue
12065     55/push-ebp
12066     89/<- %ebp 4/r32/esp
12067     # . save registers
12068 $check-mu-copy-to-stmt:end:
12069     # . restore registers
12070     # . epilogue
12071     89/<- %esp 5/r32/ebp
12072     5d/pop-to-ebp
12073     c3/return
12074 
12075 check-mu-compare-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12076     # . prologue
12077     55/push-ebp
12078     89/<- %ebp 4/r32/esp
12079     # . save registers
12080 $check-mu-compare-stmt:end:
12081     # . restore registers
12082     # . epilogue
12083     89/<- %esp 5/r32/ebp
12084     5d/pop-to-ebp
12085     c3/return
12086 
12087 check-mu-address-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12088     # . prologue
12089     55/push-ebp
12090     89/<- %ebp 4/r32/esp
12091     # . save registers
12092 $check-mu-address-stmt:end:
12093     # . restore registers
12094     # . epilogue
12095     89/<- %esp 5/r32/ebp
12096     5d/pop-to-ebp
12097     c3/return
12098 
12099 check-mu-get-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12100     # . prologue
12101     55/push-ebp
12102     89/<- %ebp 4/r32/esp
12103     # . save registers
12104     50/push-eax
12105     51/push-ecx
12106     52/push-edx
12107     53/push-ebx
12108     56/push-esi
12109     57/push-edi
12110     # esi = stmt
12111     8b/-> *(ebp+8) 6/r32/esi
12112     # - check for 0 inouts
12113     # var base/ecx: (addr var) = stmt->inouts->value
12114     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12115     3d/compare-eax-and 0/imm32/false
12116     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-inouts/disp32
12117     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12118     89/<- %ecx 0/r32/eax
12119 $check-mu-get-stmt:check-base:
12120     # - check base type
12121     # if it's an 'addr', check that it's in a register
12122     # var base-type/ebx: (addr type-tree) = lookup(base->type)
12123     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
12124     89/<- %ebx 0/r32/eax
12125     {
12126       81 7/subop/compare *ebx 0/imm32/false  # Type-tree-is-atom
12127       0f 85/jump-if-!= break/disp32
12128 $check-mu-get-stmt:base-is-compound:
12129       # if (type->left != addr) break
12130       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
12131       (is-simple-mu-type? %eax 2)  # => eax
12132       3d/compare-eax-and 0/imm32/false
12133       74/jump-if-= break/disp8
12134 $check-mu-get-stmt:base-is-addr:
12135       # now check for register
12136       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
12137       0f 84/jump-if-= $check-mu-get-stmt:error-base-type-addr-but-not-register/disp32
12138 $check-mu-get-stmt:base-is-addr-in-register:
12139       # type->left is now an addr; skip it
12140       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
12141       81 7/subop/compare *(eax+0xc) 0/imm32  # Type-tree-right
12142       0f 85/jump-if-!= $check-mu-get-stmt:error-bad-base/disp32
12143 $check-mu-get-stmt:base-is-addr-to-atom-in-register:
12144       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
12145       89/<- %ebx 0/r32/eax
12146     }
12147 $check-mu-get-stmt:check-base-typeinfo:
12148     # ensure type is a container
12149     # var base-type-id/ebx: type-id = base-type->value
12150     8b/-> *(ebx+4) 3/r32/ebx  # Type-tree-value
12151     (is-container? %ebx)  # => eax
12152     3d/compare-eax-and 0/imm32/false
12153     0f 84/jump-if-= $check-mu-get-stmt:error-bad-base/disp32
12154     # var base-typeinfo/edx: (addr typeinfo) = find-typeinfo(base-type-id)
12155     # . var container/ecx: (handle typeinfo)
12156     68/push 0/imm32
12157     68/push 0/imm32
12158     89/<- %ecx 4/r32/esp
12159     # .
12160     (find-typeinfo %ebx %ecx)
12161     (lookup *ecx *(ecx+4))  # => eax
12162     # . reclaim container
12163     81 0/subop/add %esp 8/imm32
12164     # .
12165     89/<- %edx 0/r32/eax
12166     # var offset/ecx: (addr stmt-var) = stmt->inouts->next
12167     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12168     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
12169     89/<- %ecx 0/r32/eax
12170     # - check for 1 inout
12171     3d/compare-eax-and 0/imm32/false
12172     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-inouts/disp32
12173     # var offset/ecx: (addr var) = lookup(offset->value)
12174     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12175     89/<- %ecx 0/r32/eax
12176     # - check for valid field
12177     81 7/subop/compare *(ecx+0x14) -1/imm32/uninitialized  # Var-offset
12178     0f 84/jump-if-= $check-mu-get-stmt:error-bad-field/disp32
12179     # - check for too many inouts
12180     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12181     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
12182     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
12183     3d/compare-eax-and 0/imm32/false
12184     0f 85/jump-if-!= $check-mu-get-stmt:error-too-many-inouts/disp32
12185     # var output/edi: (addr var) = stmt->outputs->value
12186     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
12187     # - check for 0 outputs
12188     3d/compare-eax-and 0/imm32/false
12189     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-outputs/disp32
12190     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12191     89/<- %edi 0/r32/eax
12192 $check-mu-get-stmt:check-output-type:
12193     # - check output type
12194     # must be in register
12195     (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
12196     3d/compare-eax-and 0/imm32
12197     0f 84/jump-if-= $check-mu-get-stmt:error-output-not-in-register/disp32
12198     # must have a non-atomic type
12199     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
12200     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
12201     0f 85/jump-if-!= $check-mu-get-stmt:error-output-type-not-address/disp32
12202     # type must start with (addr ...)
12203     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
12204     (is-simple-mu-type? %eax 2)  # => eax
12205     3d/compare-eax-and 0/imm32/false
12206     0f 84/jump-if-= $check-mu-get-stmt:error-output-type-not-address/disp32
12207 $check-mu-get-stmt:check-output-type-match:
12208     # payload of addr type must match 'type' definition
12209     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
12210     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
12211     # if (payload->right == null) payload = payload->left
12212     81 7/subop/compare *(eax+0xc) 0/imm32/null  # Type-tree-right
12213     {
12214       75/jump-if-!= break/disp8
12215       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
12216     }
12217     89/<- %edi 0/r32/eax
12218     # . var output-name/ecx: (addr array byte)
12219     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
12220     89/<- %ecx 0/r32/eax
12221     # . var base-typeinfo-entry/eax: (addr handle typeinfo-entry)
12222     (lookup *(edx+4) *(edx+8))  # Typeinfo-fields Typeinfo-fields => eax
12223     (get %eax %ecx 0x10)  # => eax
12224     # .
12225     (lookup *eax *(eax+4))  # => eax
12226     (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
12227     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12228     # .
12229     (type-equal? %edi %eax)  # => eax
12230     3d/compare-eax-and 0/imm32/false
12231     0f 84/jump-if-= $check-mu-get-stmt:error-bad-output-type/disp32
12232     # - check for too many outputs
12233     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
12234     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
12235     3d/compare-eax-and 0/imm32/false
12236     0f 85/jump-if-!= $check-mu-get-stmt:error-too-many-outputs/disp32
12237 $check-mu-get-stmt:end:
12238     # . restore registers
12239     5f/pop-to-edi
12240     5e/pop-to-esi
12241     5b/pop-to-ebx
12242     5a/pop-to-edx
12243     59/pop-to-ecx
12244     58/pop-to-eax
12245     # . epilogue
12246     89/<- %esp 5/r32/ebp
12247     5d/pop-to-ebp
12248     c3/return
12249 
12250 $check-mu-get-stmt:error-too-few-inouts:
12251     (write-buffered *(ebp+0x10) "fn ")
12252     8b/-> *(ebp+0xc) 0/r32/eax
12253     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12254     (write-buffered *(ebp+0x10) %eax)
12255     (write-buffered *(ebp+0x10) ": stmt get: too few inouts (2 required)\n")
12256     (flush *(ebp+0x10))
12257     (stop *(ebp+0x14) 1)
12258     # never gets here
12259 
12260 $check-mu-get-stmt:error-too-many-inouts:
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: too many inouts (2 required)\n")
12266     (flush *(ebp+0x10))
12267     (stop *(ebp+0x14) 1)
12268     # never gets here
12269 
12270 $check-mu-get-stmt:error-too-few-outputs:
12271     (write-buffered *(ebp+0x10) "fn ")
12272     8b/-> *(ebp+0xc) 0/r32/eax
12273     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12274     (write-buffered *(ebp+0x10) %eax)
12275     (write-buffered *(ebp+0x10) ": stmt get: must have an output\n")
12276     (flush *(ebp+0x10))
12277     (stop *(ebp+0x14) 1)
12278     # never gets here
12279 
12280 $check-mu-get-stmt:error-too-many-outputs:
12281     (write-buffered *(ebp+0x10) "fn ")
12282     8b/-> *(ebp+0xc) 0/r32/eax
12283     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12284     (write-buffered *(ebp+0x10) %eax)
12285     (write-buffered *(ebp+0x10) ": stmt get: too many outputs (1 required)\n")
12286     (flush *(ebp+0x10))
12287     (stop *(ebp+0x14) 1)
12288     # never gets here
12289 
12290 $check-mu-get-stmt:error-bad-base:
12291     # error("fn " fn ": stmt get: var '" base->name "' must have a 'type' definition\n")
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: var '")
12297     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12298     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12299     (lookup *eax *(eax+4))  # Var-name Var-name => eax
12300     (write-buffered *(ebp+0x10) %eax)
12301     (write-buffered *(ebp+0x10) "' must have a 'type' definition\n")
12302     (flush *(ebp+0x10))
12303     (stop *(ebp+0x14) 1)
12304     # never gets here
12305 
12306 $check-mu-get-stmt:error-base-type-addr-but-not-register:
12307     (write-buffered *(ebp+0x10) "fn ")
12308     8b/-> *(ebp+0xc) 0/r32/eax
12309     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12310     (write-buffered *(ebp+0x10) %eax)
12311     (write-buffered *(ebp+0x10) ": stmt get: var '")
12312     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12313     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12314     (lookup *eax *(eax+4))  # Var-name Var-name => eax
12315     (write-buffered *(ebp+0x10) %eax)
12316     (write-buffered *(ebp+0x10) "' is an 'addr' type, and so must live in a register\n")
12317     (flush *(ebp+0x10))
12318     (stop *(ebp+0x14) 1)
12319     # never gets here
12320 
12321 $check-mu-get-stmt:error-bad-field:
12322     # error("fn " fn ": stmt get: type " type " has no member called '" curr->name "'\n")
12323     (write-buffered *(ebp+0x10) "fn ")
12324     8b/-> *(ebp+0xc) 0/r32/eax
12325     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12326     (write-buffered *(ebp+0x10) %eax)
12327     (write-buffered *(ebp+0x10) ": stmt get: type '")
12328     # . write(Type-id->data[tmp])
12329     bf/copy-to-edi Type-id/imm32
12330     (write-buffered *(ebp+0x10) *(edi+ebx<<2+0xc))
12331     # .
12332     (write-buffered *(ebp+0x10) "' has no member called '")
12333     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
12334     (write-buffered *(ebp+0x10) %eax)
12335     (write-buffered *(ebp+0x10) "'\n")
12336     (flush *(ebp+0x10))
12337     (stop *(ebp+0x14) 1)
12338     # never gets here
12339 
12340 $check-mu-get-stmt:error-output-not-in-register:
12341     (write-buffered *(ebp+0x10) "fn ")
12342     8b/-> *(ebp+0xc) 0/r32/eax
12343     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12344     (write-buffered *(ebp+0x10) %eax)
12345     (write-buffered *(ebp+0x10) ": stmt get: output '")
12346     (lookup *edi *(edi+4))  # Var-name Var-name => eax
12347     (write-buffered *(ebp+0x10) %eax)
12348     (write-buffered *(ebp+0x10) "' is not in a register\n")
12349     (flush *(ebp+0x10))
12350     (stop *(ebp+0x14) 1)
12351     # never gets here
12352 
12353 $check-mu-get-stmt:error-output-type-not-address:
12354     (write-buffered *(ebp+0x10) "fn ")
12355     8b/-> *(ebp+0xc) 0/r32/eax
12356     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12357     (write-buffered *(ebp+0x10) %eax)
12358     (write-buffered *(ebp+0x10) ": stmt get: output must be an address\n")
12359     (flush *(ebp+0x10))
12360     (stop *(ebp+0x14) 1)
12361     # never gets here
12362 
12363 $check-mu-get-stmt:error-bad-output-type:
12364     (write-buffered *(ebp+0x10) "fn ")
12365     8b/-> *(ebp+0xc) 0/r32/eax
12366     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12367     (write-buffered *(ebp+0x10) %eax)
12368     (write-buffered *(ebp+0x10) ": stmt get: wrong output type for member '")
12369     (write-buffered *(ebp+0x10) %ecx)
12370     (write-buffered *(ebp+0x10) "' of type '")
12371     bf/copy-to-edi Type-id/imm32
12372     (write-buffered *(ebp+0x10) *(edi+ebx<<2+0xc))
12373     (write-buffered *(ebp+0x10) "'\n")
12374     (flush *(ebp+0x10))
12375     (stop *(ebp+0x14) 1)
12376     # never gets here
12377 
12378 check-mu-index-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12379     # . prologue
12380     55/push-ebp
12381     89/<- %ebp 4/r32/esp
12382     # . save registers
12383 $check-mu-index-stmt:end:
12384     # . restore registers
12385     # . epilogue
12386     89/<- %esp 5/r32/ebp
12387     5d/pop-to-ebp
12388     c3/return
12389 
12390 check-mu-length-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12391     # . prologue
12392     55/push-ebp
12393     89/<- %ebp 4/r32/esp
12394     # . save registers
12395 $check-mu-length-stmt:end:
12396     # . restore registers
12397     # . epilogue
12398     89/<- %esp 5/r32/ebp
12399     5d/pop-to-ebp
12400     c3/return
12401 
12402 check-mu-compute-offset-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12403     # . prologue
12404     55/push-ebp
12405     89/<- %ebp 4/r32/esp
12406     # . save registers
12407 $check-mu-compute-offset-stmt:end:
12408     # . restore registers
12409     # . epilogue
12410     89/<- %esp 5/r32/ebp
12411     5d/pop-to-ebp
12412     c3/return
12413 
12414 check-mu-allocate-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12415     # . prologue
12416     55/push-ebp
12417     89/<- %ebp 4/r32/esp
12418     # . save registers
12419 $check-mu-allocate-stmt:end:
12420     # . restore registers
12421     # . epilogue
12422     89/<- %esp 5/r32/ebp
12423     5d/pop-to-ebp
12424     c3/return
12425 
12426 check-mu-populate-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12427     # . prologue
12428     55/push-ebp
12429     89/<- %ebp 4/r32/esp
12430     # . save registers
12431 $check-mu-populate-stmt:end:
12432     # . restore registers
12433     # . epilogue
12434     89/<- %esp 5/r32/ebp
12435     5d/pop-to-ebp
12436     c3/return
12437 
12438 check-mu-populate-stream-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12439     # . prologue
12440     55/push-ebp
12441     89/<- %ebp 4/r32/esp
12442     # . save registers
12443 $check-mu-populate-stream-stmt:end:
12444     # . restore registers
12445     # . epilogue
12446     89/<- %esp 5/r32/ebp
12447     5d/pop-to-ebp
12448     c3/return
12449 
12450 check-mu-read-from-stream-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12451     # . prologue
12452     55/push-ebp
12453     89/<- %ebp 4/r32/esp
12454     # . save registers
12455 $check-mu-read-from-stream-stmt:end:
12456     # . restore registers
12457     # . epilogue
12458     89/<- %esp 5/r32/ebp
12459     5d/pop-to-ebp
12460     c3/return
12461 
12462 check-mu-write-to-stream-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12463     # . prologue
12464     55/push-ebp
12465     89/<- %ebp 4/r32/esp
12466     # . save registers
12467 $check-mu-write-to-stream-stmt:end:
12468     # . restore registers
12469     # . epilogue
12470     89/<- %esp 5/r32/ebp
12471     5d/pop-to-ebp
12472     c3/return
12473 
12474 check-mu-call:  # stmt: (addr stmt), callee: (addr function), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12475     # . prologue
12476     55/push-ebp
12477     89/<- %ebp 4/r32/esp
12478     # var type-parameters: (addr table (handle array byte) (addr type-tree) 8)
12479     68/push 0/imm32
12480     # var type-parameters-storage: (table (handle array byte) (addr type-tree) 8)
12481     81 5/subop/subtract %esp 0x60/imm32
12482     68/push 0x60/imm32/size
12483     68/push 0/imm32/read
12484     68/push 0/imm32/write
12485     # save a pointer to type-parameters-storage at type-parameters
12486     89/<- *(ebp-4) 4/r32/esp
12487     (clear-stream *(ebp-4))
12488     # . save registers
12489     50/push-eax
12490     51/push-ecx
12491     52/push-edx
12492     53/push-ebx
12493     56/push-esi
12494     57/push-edi
12495     # esi = stmt
12496     8b/-> *(ebp+8) 6/r32/esi
12497     # edi = callee
12498     8b/-> *(ebp+0xc) 7/r32/edi
12499     # var inouts/ecx: (addr stmt-var) = lookup(stmt->inouts)
12500     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12501     89/<- %ecx 0/r32/eax
12502     # var expected/edx: (addr list var) = lookup(f->inouts)
12503     (lookup *(edi+8) *(edi+0xc))  # Function-inouts Function-inouts => eax
12504     89/<- %edx 0/r32/eax
12505     {
12506 $check-mu-call:check-for-inouts:
12507       # if (inouts == 0) break
12508       81 7/subop/compare %ecx 0/imm32
12509       0f 84/jump-if-= break/disp32
12510       # if (expected == 0) error
12511       81 7/subop/compare %edx 0/imm32
12512       0f 84/jump-if-= break/disp32
12513 $check-mu-call:check-inout-type:
12514       # var v/eax: (addr v) = lookup(inouts->value)
12515       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12516       # var t/ebx: (addr type-tree) = lookup(v->type)
12517       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12518       89/<- %ebx 0/r32/eax
12519       # if (inouts->is-deref?) t = t->right  # TODO: check that t->left is an addr
12520       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
12521       {
12522         74/jump-if-= break/disp8
12523         (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
12524         89/<- %ebx 0/r32/eax
12525         # if t->right is null, t = t->left
12526         81 7/subop/compare *(ebx+0xc) 0/imm32  # Type-tree-right
12527         75/jump-if-!= break/disp8
12528         (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
12529         89/<- %ebx 0/r32/eax
12530       }
12531       # var v2/eax: (addr v) = lookup(expected->value)
12532       (lookup *edx *(edx+4))  # List-value List-value => eax
12533       # var t2/eax: (addr type-tree) = lookup(v2->type)
12534       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12535       # if (t != t2) error
12536       (type-match? %eax %ebx *(ebp-4))  # => eax
12537       3d/compare-eax-and 0/imm32/false
12538       {
12539         0f 85/jump-if-!= break/disp32
12540         (write-buffered *(ebp+0x14) "fn ")
12541         8b/-> *(ebp+0x10) 0/r32/eax
12542         (lookup *eax *(eax+4))  # Function-name Function-name => eax
12543         (write-buffered *(ebp+0x14) %eax)
12544         (write-buffered *(ebp+0x14) ": call ")
12545         (lookup *edi *(edi+4))  # Function-name Function-name => eax
12546         (write-buffered *(ebp+0x14) %eax)
12547         (write-buffered *(ebp+0x14) ": type for inout '")
12548         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12549         (lookup *eax *(eax+4))  # Var-name Var-name => eax
12550         (write-buffered *(ebp+0x14) %eax)
12551         (write-buffered *(ebp+0x14) "' is not right\n")
12552         (flush *(ebp+0x14))
12553         (stop *(ebp+0x18) 1)
12554       }
12555 $check-mu-call:continue-to-next-inout:
12556       # inouts = lookup(inouts->next)
12557       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
12558       89/<- %ecx 0/r32/eax
12559       # expected = lookup(expected->next)
12560       (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
12561       89/<- %edx 0/r32/eax
12562       #
12563       e9/jump loop/disp32
12564     }
12565 $check-mu-call:check-inout-count:
12566     # if (inouts == expected) proceed
12567     39/compare %ecx 2/r32/edx
12568     {
12569       0f 84/jump-if-= break/disp32
12570       # exactly one of the two is null
12571       # if (inouts == 0) error("too many inouts")
12572       {
12573         81 7/subop/compare %ecx 0/imm32
12574         0f 84/jump-if-= break/disp32
12575         (write-buffered *(ebp+0x14) "fn ")
12576         8b/-> *(ebp+0x10) 0/r32/eax
12577         (lookup *eax *(eax+4))  # Function-name Function-name => eax
12578         (write-buffered *(ebp+0x14) %eax)
12579         (write-buffered *(ebp+0x14) ": call ")
12580         (lookup *edi *(edi+4))  # Function-name Function-name => eax
12581         (write-buffered *(ebp+0x14) %eax)
12582         (write-buffered *(ebp+0x14) ": too many inouts\n")
12583         (flush *(ebp+0x14))
12584         (stop *(ebp+0x18) 1)
12585       }
12586       # if (expected == 0) error("too few inouts")
12587       {
12588         81 7/subop/compare %edx 0/imm32
12589         0f 84/jump-if-= break/disp32
12590         (write-buffered *(ebp+0x14) "fn ")
12591         8b/-> *(ebp+0x10) 0/r32/eax
12592         (lookup *eax *(eax+4))  # Function-name Function-name => eax
12593         (write-buffered *(ebp+0x14) %eax)
12594         (write-buffered *(ebp+0x14) ": call ")
12595         (lookup *edi *(edi+4))  # Function-name Function-name => eax
12596         (write-buffered *(ebp+0x14) %eax)
12597         (write-buffered *(ebp+0x14) ": too few inouts\n")
12598         (flush *(ebp+0x14))
12599         (stop *(ebp+0x18) 1)
12600       }
12601     }
12602 $check-mu-call:check-outputs:
12603     # var outputs/ecx: (addr stmt-var) = lookup(stmt->outputs)
12604     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
12605     89/<- %ecx 0/r32/eax
12606     # var expected/edx: (addr list var) = lookup(f->outputs)
12607     (lookup *(edi+0x10) *(edi+0x14))  # Function-outputs Function-outputs => eax
12608     89/<- %edx 0/r32/eax
12609     {
12610 $check-mu-call:check-for-outputs:
12611       # if (outputs == 0) break
12612       81 7/subop/compare %ecx 0/imm32
12613       0f 84/jump-if-= break/disp32
12614       # if (expected == 0) error
12615       81 7/subop/compare %edx 0/imm32
12616       0f 84/jump-if-= break/disp32
12617 $check-mu-call:check-output-type:
12618       # var v/eax: (addr v) = lookup(outputs->value)
12619       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12620       # var t/ebx: (addr type-tree) = lookup(v->type)
12621       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12622       89/<- %ebx 0/r32/eax
12623       # if (outputs->is-deref?) t = t->right  # TODO: check that t->left is an addr
12624       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
12625       {
12626         74/jump-if-= break/disp8
12627         (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
12628         89/<- %ebx 0/r32/eax
12629       }
12630       # var v2/eax: (addr v) = lookup(expected->value)
12631       (lookup *edx *(edx+4))  # List-value List-value => eax
12632       # var t2/eax: (addr type-tree) = lookup(v2->type)
12633       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12634       # if (t != t2) error
12635       (type-match? %eax %ebx *(ebp-4))  # => eax
12636       3d/compare-eax-and 0/imm32/false
12637       {
12638         0f 85/jump-if-!= break/disp32
12639         (write-buffered *(ebp+0x14) "fn ")
12640         8b/-> *(ebp+0x10) 0/r32/eax
12641         (lookup *eax *(eax+4))  # Function-name Function-name => eax
12642         (write-buffered *(ebp+0x14) %eax)
12643         (write-buffered *(ebp+0x14) ": call ")
12644         (lookup *edi *(edi+4))  # Function-name Function-name => eax
12645         (write-buffered *(ebp+0x14) %eax)
12646         (write-buffered *(ebp+0x14) ": type for output '")
12647         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12648         (lookup *eax *(eax+4))  # Var-name Var-name => eax
12649         (write-buffered *(ebp+0x14) %eax)
12650         (write-buffered *(ebp+0x14) "' is not right\n")
12651         (flush *(ebp+0x14))
12652         (stop *(ebp+0x18) 1)
12653       }
12654 $check-mu-call:check-output-register:
12655       # var v/eax: (addr v) = lookup(outputs->value)
12656       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12657       # var r/ebx: (addr array byte) = lookup(v->register)
12658       (lookup *(eax+18) *(eax+0x1c))  # Var-register Var-register => eax
12659       89/<- %ebx 0/r32/eax
12660       # var v2/eax: (addr v) = lookup(expected->value)
12661       (lookup *edx *(edx+4))  # Stmt-var-value Stmt-var-value => eax
12662       # var r2/eax: (addr array byte) = lookup(v2->register)
12663       (lookup *(eax+18) *(eax+0x1c))  # Var-register Var-register => eax
12664       # if (r != r2) error
12665       (string-equal? %eax %ebx)  # => eax
12666       3d/compare-eax-and 0/imm32/false
12667       {
12668         0f 85/jump-if-!= break/disp32
12669         (write-buffered *(ebp+0x14) "fn ")
12670         8b/-> *(ebp+0x10) 0/r32/eax
12671         (lookup *eax *(eax+4))  # Function-name Function-name => eax
12672         (write-buffered *(ebp+0x14) %eax)
12673         (write-buffered *(ebp+0x14) ": call ")
12674         (lookup *edi *(edi+4))  # Function-name Function-name => eax
12675         (write-buffered *(ebp+0x14) %eax)
12676         (write-buffered *(ebp+0x14) ": register for output '")
12677         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12678         (lookup *eax *(eax+4))  # Var-name Var-name => eax
12679         (write-buffered *(ebp+0x14) %eax)
12680         (write-buffered *(ebp+0x14) "' is not right\n")
12681         (flush *(ebp+0x14))
12682         (stop *(ebp+0x18) 1)
12683       }
12684 $check-mu-call:continue-to-next-output:
12685       # outputs = lookup(outputs->next)
12686       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
12687       89/<- %ecx 0/r32/eax
12688       # expected = lookup(expected->next)
12689       (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
12690       89/<- %edx 0/r32/eax
12691       #
12692       e9/jump loop/disp32
12693     }
12694 $check-mu-call:check-output-count:
12695     # if (outputs == expected) proceed
12696     39/compare %ecx 2/r32/edx
12697     {
12698       0f 84/jump-if-= break/disp32
12699       # exactly one of the two is null
12700       # if (outputs == 0) error("too many outputs")
12701       {
12702         81 7/subop/compare %ecx 0/imm32
12703         0f 84/jump-if-= break/disp32
12704         (write-buffered *(ebp+0x14) "fn ")
12705         8b/-> *(ebp+0x10) 0/r32/eax
12706         (lookup *eax *(eax+4))  # Function-name Function-name => eax
12707         (write-buffered *(ebp+0x14) %eax)
12708         (write-buffered *(ebp+0x14) ": call ")
12709         (lookup *edi *(edi+4))  # Function-name Function-name => eax
12710         (write-buffered *(ebp+0x14) %eax)
12711         (write-buffered *(ebp+0x14) ": too many outputs\n")
12712         (flush *(ebp+0x14))
12713         (stop *(ebp+0x18) 1)
12714       }
12715       # if (expected == 0) error("too few outputs")
12716       {
12717         81 7/subop/compare %edx 0/imm32
12718         0f 84/jump-if-= break/disp32
12719         (write-buffered *(ebp+0x14) "fn ")
12720         8b/-> *(ebp+0x10) 0/r32/eax
12721         (lookup *eax *(eax+4))  # Function-name Function-name => eax
12722         (write-buffered *(ebp+0x14) %eax)
12723         (write-buffered *(ebp+0x14) ": call ")
12724         (lookup *edi *(edi+4))  # Function-name Function-name => eax
12725         (write-buffered *(ebp+0x14) %eax)
12726         (write-buffered *(ebp+0x14) ": too few outputs\n")
12727         (flush *(ebp+0x14))
12728         (stop *(ebp+0x18) 1)
12729       }
12730     }
12731 $check-mu-call:end:
12732     # . restore registers
12733     5f/pop-to-edi
12734     5e/pop-to-esi
12735     5b/pop-to-ebx
12736     5a/pop-to-edx
12737     59/pop-to-ecx
12738     58/pop-to-eax
12739     # . reclaim locals exclusively on the stack
12740     81 0/subop/add %esp 0x70/imm32
12741     # . epilogue
12742     89/<- %esp 5/r32/ebp
12743     5d/pop-to-ebp
12744     c3/return
12745 
12746 # like type-equal? but takes literals into account
12747 type-match?:  # def: (addr type-tree), call: (addr type-tree), type-parameters: (addr table (handle array byte) (addr type-tree)) -> result/eax: boolean
12748     # . prologue
12749     55/push-ebp
12750     89/<- %ebp 4/r32/esp
12751     # if (call == literal) return true  # TODO: more precise
12752     (is-simple-mu-type? *(ebp+0xc) 0)  # literal => eax
12753     3d/compare-eax-and 0/imm32/false
12754     b8/copy-to-eax 1/imm32/true
12755     75/jump-if-!= $type-match?:end/disp8
12756 $type-match?:baseline:
12757     # otherwise fall back
12758     (type-component-match? *(ebp+8) *(ebp+0xc) *(ebp+0x10))  # => eax
12759 $type-match?:end:
12760     # . epilogue
12761     89/<- %esp 5/r32/ebp
12762     5d/pop-to-ebp
12763     c3/return
12764 
12765 type-component-match?:  # def: (addr type-tree), call: (addr type-tree), type-parameters: (addr table (handle array byte) (addr type-tree)) -> result/eax: boolean
12766     # . prologue
12767     55/push-ebp
12768     89/<- %ebp 4/r32/esp
12769     # . save registers
12770     51/push-ecx
12771     52/push-edx
12772     53/push-ebx
12773     # ecx = def
12774     8b/-> *(ebp+8) 1/r32/ecx
12775     # edx = call
12776     8b/-> *(ebp+0xc) 2/r32/edx
12777 $type-component-match?:compare-addr:
12778     # if (def == call) return true
12779     8b/-> %ecx 0/r32/eax  # Var-type
12780     39/compare %edx 0/r32/eax  # Var-type
12781     b8/copy-to-eax 1/imm32/true
12782     0f 84/jump-if-= $type-component-match?:end/disp32
12783     # if def is a type parameter, return true
12784     {
12785 $type-component-match?:check-type-parameter:
12786       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
12787       74/jump-if-= break/disp8
12788       81 7/subop/compare *(ecx+4) 0xa/imm32/type-parameter  # Type-tree-value
12789       75/jump-if-!= break/disp8
12790 $type-component-match?:type-parameter:
12791       (type-parameter-match? *(ecx+8) *(ecx+0xc)  %edx  *(ebp+0x10))  # => eax
12792       e9/jump $type-component-match?:end/disp32
12793     }
12794 $type-component-match?:compare-atom-state:
12795     # if (def->is-atom? != call->is-atom?) return false
12796     8b/-> *ecx 3/r32/ebx  # Type-tree-is-atom
12797     39/compare *edx 3/r32/ebx  # Type-tree-is-atom
12798     b8/copy-to-eax 0/imm32/false
12799     0f 85/jump-if-!= $type-component-match?:end/disp32
12800     # if def->is-atom? return (def->value == call->value)
12801     {
12802 $type-component-match?:check-atom:
12803       81 7/subop/compare %ebx 0/imm32/false
12804       74/jump-if-= break/disp8
12805 $type-component-match?:is-atom:
12806       8b/-> *(ecx+4) 0/r32/eax  # Type-tree-value
12807       39/compare *(edx+4) 0/r32/eax  # Type-tree-value
12808       0f 94/set-if-= %al
12809       81 4/subop/and %eax 0xff/imm32
12810       e9/jump $type-component-match?:end/disp32
12811     }
12812 $type-component-match?:check-left:
12813     # if (!type-component-match?(def->left, call->left)) return false
12814     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
12815     89/<- %ebx 0/r32/eax
12816     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
12817     (type-component-match? %ebx %eax *(ebp+0x10))  # => eax
12818     3d/compare-eax-and 0/imm32/false
12819     74/jump-if-= $type-component-match?:end/disp8
12820 $type-component-match?:check-right:
12821     # return type-component-match?(def->right, call->right)
12822     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
12823     89/<- %ebx 0/r32/eax
12824     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
12825     (type-component-match? %ebx %eax *(ebp+0x10))  # => eax
12826 $type-component-match?:end:
12827     # . restore registers
12828     5b/pop-to-ebx
12829     5a/pop-to-edx
12830     59/pop-to-ecx
12831     # . epilogue
12832     89/<- %esp 5/r32/ebp
12833     5d/pop-to-ebp
12834     c3/return
12835 
12836 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
12837     # . prologue
12838     55/push-ebp
12839     89/<- %ebp 4/r32/esp
12840     # . save registers
12841     51/push-ecx
12842     #
12843     (get-or-insert-handle *(ebp+0x14)  *(ebp+8) *(ebp+0xc)  0xc)  # => eax
12844     # if parameter wasn't saved, save it
12845     {
12846       81 7/subop/compare *eax 0/imm32
12847       75/jump-if-!= break/disp8
12848       8b/-> *(ebp+0x10) 1/r32/ecx
12849       89/<- *eax 1/r32/ecx
12850     }
12851     #
12852     (type-equal? *(ebp+0x10) *eax)  # => eax
12853 $type-parameter-match?:end:
12854     # . restore registers
12855     59/pop-to-ecx
12856     # . epilogue
12857     89/<- %esp 5/r32/ebp
12858     5d/pop-to-ebp
12859     c3/return
12860 
12861 size-of:  # v: (addr var) -> result/eax: int
12862     # . prologue
12863     55/push-ebp
12864     89/<- %ebp 4/r32/esp
12865     # . save registers
12866     51/push-ecx
12867     # var t/ecx: (addr type-tree) = lookup(v->type)
12868     8b/-> *(ebp+8) 1/r32/ecx
12869 #?     (write-buffered Stderr "size-of ")
12870 #?     (write-int32-hex-buffered Stderr %ecx)
12871 #?     (write-buffered Stderr Newline)
12872 #?     (write-buffered Stderr "type allocid: ")
12873 #?     (write-int32-hex-buffered Stderr *(ecx+8))
12874 #?     (write-buffered Stderr Newline)
12875 #?     (flush Stderr)
12876     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
12877     89/<- %ecx 0/r32/eax
12878     # if is-mu-array?(t) return size-of-array(t)
12879     {
12880       (is-mu-array? %ecx)  # => eax
12881       3d/compare-eax-and 0/imm32/false
12882       74/jump-if-= break/disp8
12883       (size-of-array %ecx)  # => eax
12884       eb/jump $size-of:end/disp8
12885     }
12886     # if is-mu-stream?(t) return size-of-stream(t)
12887     {
12888       (is-mu-stream? %ecx)  # => eax
12889       3d/compare-eax-and 0/imm32/false
12890       74/jump-if-= break/disp8
12891       (size-of-stream %ecx)  # => eax
12892       eb/jump $size-of:end/disp8
12893     }
12894     # if (!t->is-atom?) t = lookup(t->left)
12895     {
12896       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
12897       75/jump-if-!= break/disp8
12898       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
12899       89/<- %ecx 0/r32/eax
12900     }
12901     # TODO: assert t->is-atom?
12902     (size-of-type-id *(ecx+4))  # Type-tree-value => eax
12903 $size-of:end:
12904     # . restore registers
12905     59/pop-to-ecx
12906     # . epilogue
12907     89/<- %esp 5/r32/ebp
12908     5d/pop-to-ebp
12909     c3/return
12910 
12911 size-of-deref:  # v: (addr var) -> result/eax: int
12912     # . prologue
12913     55/push-ebp
12914     89/<- %ebp 4/r32/esp
12915     # . save registers
12916     51/push-ecx
12917     # var t/ecx: (addr type-tree) = lookup(v->type)
12918     8b/-> *(ebp+8) 1/r32/ecx
12919     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
12920     89/<- %ecx 0/r32/eax
12921     # TODO: assert(t is an addr)
12922     # t = lookup(t->right)
12923     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
12924     89/<- %ecx 0/r32/eax
12925     # if is-mu-array?(t) return size-of-array(t)
12926     {
12927       (is-mu-array? %ecx)  # => eax
12928       3d/compare-eax-and 0/imm32/false
12929       74/jump-if-= break/disp8
12930       (size-of-array %ecx)  # => eax
12931       eb/jump $size-of-deref:end/disp8
12932     }
12933     # if is-mu-stream?(t) return size-of-stream(t)
12934     {
12935       (is-mu-stream? %ecx)  # => eax
12936       3d/compare-eax-and 0/imm32/false
12937       74/jump-if-= break/disp8
12938       (size-of-stream %ecx)  # => eax
12939       eb/jump $size-of-deref:end/disp8
12940     }
12941     # if (!t->is-atom?) t = lookup(t->left)
12942     {
12943       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
12944       75/jump-if-!= break/disp8
12945       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
12946       89/<- %ecx 0/r32/eax
12947     }
12948     # TODO: assert t->is-atom?
12949     (size-of-type-id *(ecx+4))  # Type-tree-value => eax
12950 $size-of-deref:end:
12951     # . restore registers
12952     59/pop-to-ecx
12953     # . epilogue
12954     89/<- %esp 5/r32/ebp
12955     5d/pop-to-ebp
12956     c3/return
12957 
12958 is-mu-array?:  # t: (addr type-tree) -> result/eax: boolean
12959     # . prologue
12960     55/push-ebp
12961     89/<- %ebp 4/r32/esp
12962     # . save registers
12963     51/push-ecx
12964     # ecx = t
12965     8b/-> *(ebp+8) 1/r32/ecx
12966     # if t->is-atom?, return false
12967     81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
12968     75/jump-if-!= $is-mu-array?:return-false/disp8
12969     # if !t->left->is-atom?, return false
12970     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
12971     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
12972     74/jump-if-= $is-mu-array?:return-false/disp8
12973     # return t->left->value == array
12974     81 7/subop/compare *(eax+4) 3/imm32/array-type-id  # Type-tree-value
12975     0f 94/set-if-= %al
12976     81 4/subop/and %eax 0xff/imm32
12977     eb/jump $is-mu-array?:end/disp8
12978 $is-mu-array?:return-false:
12979     b8/copy-to-eax 0/imm32/false
12980 $is-mu-array?:end:
12981     # . restore registers
12982     59/pop-to-ecx
12983     # . epilogue
12984     89/<- %esp 5/r32/ebp
12985     5d/pop-to-ebp
12986     c3/return
12987 
12988 # size of a statically allocated array where the size is part of the type expression
12989 size-of-array:  # a: (addr type-tree) -> result/eax: int
12990     # . prologue
12991     55/push-ebp
12992     89/<- %ebp 4/r32/esp
12993     # . save registers
12994     51/push-ecx
12995     52/push-edx
12996     #
12997     8b/-> *(ebp+8) 1/r32/ecx
12998     # TODO: assert that a->left is 'array'
12999     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
13000     89/<- %ecx 0/r32/eax
13001     # var elem-type/edx: type-id = a->right->left->value
13002     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
13003     8b/-> *(eax+4) 2/r32/edx  # Type-tree-value
13004     # TODO: assert that a->right->right->left->value == size
13005     # var array-size/ecx: int = a->right->right->left->value-size
13006     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
13007     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
13008     8b/-> *(eax+8) 1/r32/ecx  # Type-tree-value-size
13009     # return 4 + array-size * size-of(elem-type)
13010     (size-of-type-id-as-array-element %edx)  # => eax
13011     f7 4/subop/multiply-into-eax %ecx
13012     05/add-to-eax 4/imm32  # for array size
13013 $size-of-array:end:
13014     # . restore registers
13015     5a/pop-to-edx
13016     59/pop-to-ecx
13017     # . epilogue
13018     89/<- %esp 5/r32/ebp
13019     5d/pop-to-ebp
13020     c3/return
13021 
13022 is-mu-stream?:  # t: (addr type-tree) -> result/eax: boolean
13023     # . prologue
13024     55/push-ebp
13025     89/<- %ebp 4/r32/esp
13026     # . save registers
13027     51/push-ecx
13028     # ecx = t
13029     8b/-> *(ebp+8) 1/r32/ecx
13030     # if t->is-atom?, return false
13031     81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
13032     75/jump-if-!= $is-mu-stream?:return-false/disp8
13033     # if !t->left->is-atom?, return false
13034     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
13035     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
13036     74/jump-if-= $is-mu-stream?:return-false/disp8
13037     # return t->left->value == stream
13038     81 7/subop/compare *(eax+4) 0xb/imm32/stream-type-id  # Type-tree-value
13039     0f 94/set-if-= %al
13040     81 4/subop/and %eax 0xff/imm32
13041     eb/jump $is-mu-stream?:end/disp8
13042 $is-mu-stream?:return-false:
13043     b8/copy-to-eax 0/imm32/false
13044 $is-mu-stream?:end:
13045     # . restore registers
13046     59/pop-to-ecx
13047     # . epilogue
13048     89/<- %esp 5/r32/ebp
13049     5d/pop-to-ebp
13050     c3/return
13051 
13052 # size of a statically allocated stream where the size is part of the type expression
13053 size-of-stream:  # a: (addr type-tree) -> result/eax: int
13054     # . prologue
13055     55/push-ebp
13056     89/<- %ebp 4/r32/esp
13057     #
13058     (size-of-array *(ebp+8))  # assumes we ignore the actual type name 'array' in the type
13059     05/add-to-eax 8/imm32  # for read/write pointers
13060 $size-of-stream:end:
13061     # . epilogue
13062     89/<- %esp 5/r32/ebp
13063     5d/pop-to-ebp
13064     c3/return
13065 
13066 size-of-type-id:  # t: type-id -> result/eax: int
13067     # . prologue
13068     55/push-ebp
13069     89/<- %ebp 4/r32/esp
13070     # . save registers
13071     51/push-ecx
13072     # var out/ecx: (handle typeinfo)
13073     68/push 0/imm32
13074     68/push 0/imm32
13075     89/<- %ecx 4/r32/esp
13076     # eax = t
13077     8b/-> *(ebp+8) 0/r32/eax
13078     # if t is a literal, return 0
13079     3d/compare-eax-and 0/imm32
13080     0f 84/jump-if-= $size-of-type-id:end/disp32  # eax changes type from type-id to int
13081     # if t is a byte, return 4 (because we don't really support non-multiples of 4)
13082     3d/compare-eax-and 8/imm32/byte
13083     {
13084       75/jump-if-!= break/disp8
13085       b8/copy-to-eax 4/imm32
13086       eb/jump $size-of-type-id:end/disp8
13087     }
13088     # if t is a handle, return 8
13089     3d/compare-eax-and 4/imm32/handle
13090     {
13091       75/jump-if-!= break/disp8
13092       b8/copy-to-eax 8/imm32
13093       eb/jump $size-of-type-id:end/disp8  # eax changes type from type-id to int
13094     }
13095     # if t is a user-defined type, return its size
13096     # TODO: support non-atom type
13097     (find-typeinfo %eax %ecx)
13098     {
13099       81 7/subop/compare *ecx 0/imm32
13100       74/jump-if-= break/disp8
13101 $size-of-type-id:user-defined:
13102       (lookup *ecx *(ecx+4))  # => eax
13103       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
13104       eb/jump $size-of-type-id:end/disp8
13105     }
13106     # otherwise return the word size
13107     b8/copy-to-eax 4/imm32
13108 $size-of-type-id:end:
13109     # . reclaim locals
13110     81 0/subop/add %esp 8/imm32
13111     # . restore registers
13112     59/pop-to-ecx
13113     # . epilogue
13114     89/<- %esp 5/r32/ebp
13115     5d/pop-to-ebp
13116     c3/return
13117 
13118 type-equal?:  # a: (addr type-tree), b: (addr type-tree) -> result/eax: boolean
13119     # . prologue
13120     55/push-ebp
13121     89/<- %ebp 4/r32/esp
13122     # . save registers
13123     51/push-ecx
13124     52/push-edx
13125     53/push-ebx
13126     # ecx = a
13127     8b/-> *(ebp+8) 1/r32/ecx
13128     # edx = b
13129     8b/-> *(ebp+0xc) 2/r32/edx
13130 $type-equal?:compare-addr:
13131     # if (a == b) return true
13132     8b/-> %ecx 0/r32/eax  # Var-type
13133     39/compare %edx 0/r32/eax  # Var-type
13134     b8/copy-to-eax 1/imm32/true
13135     0f 84/jump-if-= $type-equal?:end/disp32
13136 $type-equal?:compare-atom-state:
13137     # if (a->is-atom? != b->is-atom?) return false
13138     8b/-> *ecx 3/r32/ebx  # Type-tree-is-atom
13139     39/compare *edx 3/r32/ebx  # Type-tree-is-atom
13140     b8/copy-to-eax 0/imm32/false
13141     0f 85/jump-if-!= $type-equal?:end/disp32
13142     # if a->is-atom? return (a->value == b->value)
13143     {
13144 $type-equal?:check-atom:
13145       81 7/subop/compare %ebx 0/imm32/false
13146       74/jump-if-= break/disp8
13147 $type-equal?:is-atom:
13148       8b/-> *(ecx+4) 0/r32/eax  # Type-tree-value
13149       39/compare *(edx+4) 0/r32/eax  # Type-tree-value
13150       0f 94/set-if-= %al
13151       81 4/subop/and %eax 0xff/imm32
13152       e9/jump $type-equal?:end/disp32
13153     }
13154 $type-equal?:check-left:
13155     # if (!type-equal?(a->left, b->left)) return false
13156     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
13157     89/<- %ebx 0/r32/eax
13158     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
13159     (type-equal? %eax %ebx)  # => eax
13160     3d/compare-eax-and 0/imm32/false
13161     74/jump-if-= $type-equal?:end/disp8
13162 $type-equal?:check-right:
13163     # return type-equal?(a->right, b->right)
13164     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
13165     89/<- %ebx 0/r32/eax
13166     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
13167     (type-equal? %eax %ebx)  # => eax
13168 $type-equal?:end:
13169     # . restore registers
13170     5b/pop-to-ebx
13171     5a/pop-to-edx
13172     59/pop-to-ecx
13173     # . epilogue
13174     89/<- %esp 5/r32/ebp
13175     5d/pop-to-ebp
13176     c3/return
13177 
13178 #######################################################
13179 # Code-generation
13180 #######################################################
13181 
13182 == data
13183 
13184 # Global state added to each var record when performing code-generation.
13185 Curr-local-stack-offset:  # (addr int)
13186     0/imm32
13187 
13188 == code
13189 
13190 emit-subx:  # out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
13191     # . prologue
13192     55/push-ebp
13193     89/<- %ebp 4/r32/esp
13194     # . save registers
13195     50/push-eax
13196     # var curr/eax: (addr function) = *Program->functions
13197     (lookup *_Program-functions *_Program-functions->payload)  # => eax
13198     {
13199       # if (curr == null) break
13200       3d/compare-eax-and 0/imm32
13201       0f 84/jump-if-= break/disp32
13202       (emit-subx-function *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))
13203       # curr = lookup(curr->next)
13204       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
13205       e9/jump loop/disp32
13206     }
13207 $emit-subx:end:
13208     # . restore registers
13209     58/pop-to-eax
13210     # . epilogue
13211     89/<- %esp 5/r32/ebp
13212     5d/pop-to-ebp
13213     c3/return
13214 
13215 emit-subx-function:  # out: (addr buffered-file), f: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13216     # . prologue
13217     55/push-ebp
13218     89/<- %ebp 4/r32/esp
13219     # some preprocessing
13220     (populate-mu-type-offsets-in-inouts *(ebp+0xc))
13221     # . save registers
13222     50/push-eax
13223     51/push-ecx
13224     52/push-edx
13225     # initialize some global state
13226     c7 0/subop/copy *Curr-block-depth 1/imm32  # Important: keep this in sync with the parse phase
13227     c7 0/subop/copy *Curr-local-stack-offset 0/imm32
13228     # ecx = f
13229     8b/-> *(ebp+0xc) 1/r32/ecx
13230     # var vars/edx: (stack (addr var) 256)
13231     81 5/subop/subtract %esp 0xc00/imm32
13232     68/push 0xc00/imm32/size
13233     68/push 0/imm32/top
13234     89/<- %edx 4/r32/esp
13235     # var name/eax: (addr array byte) = lookup(f->name)
13236     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
13237     #
13238     (write-buffered *(ebp+8) %eax)
13239     (write-buffered *(ebp+8) ":\n")
13240     (emit-subx-prologue *(ebp+8))
13241     # var body/eax: (addr block) = lookup(f->body)
13242     (lookup *(ecx+0x18) *(ecx+0x1c))  # Function-body Function-body => eax
13243     #
13244     (emit-subx-block *(ebp+8) %eax %edx *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13245     (emit-subx-epilogue *(ebp+8))
13246     # TODO: validate that *Curr-block-depth and *Curr-local-stack-offset have
13247     # been cleaned up
13248 $emit-subx-function:end:
13249     # . reclaim locals
13250     81 0/subop/add %esp 0xc08/imm32
13251     # . restore registers
13252     5a/pop-to-edx
13253     59/pop-to-ecx
13254     58/pop-to-eax
13255     # . epilogue
13256     89/<- %esp 5/r32/ebp
13257     5d/pop-to-ebp
13258     c3/return
13259 
13260 populate-mu-type-offsets-in-inouts:  # f: (addr function)
13261     # . prologue
13262     55/push-ebp
13263     89/<- %ebp 4/r32/esp
13264     # . save registers
13265     50/push-eax
13266     51/push-ecx
13267     52/push-edx
13268     53/push-ebx
13269     57/push-edi
13270     # var next-offset/edx: int = 8
13271     ba/copy-to-edx 8/imm32
13272     # var curr/ecx: (addr list var) = lookup(f->inouts)
13273     8b/-> *(ebp+8) 1/r32/ecx
13274     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
13275     89/<- %ecx 0/r32/eax
13276     {
13277 $populate-mu-type-offsets-in-inouts:loop:
13278       81 7/subop/compare %ecx 0/imm32
13279       74/jump-if-= break/disp8
13280       # var v/ebx: (addr var) = lookup(curr->value)
13281       (lookup *ecx *(ecx+4))  # List-value List-value => eax
13282       89/<- %ebx 0/r32/eax
13283 #?       (lookup *ebx *(ebx+4))
13284 #?       (write-buffered Stderr "setting offset of fn inout ")
13285 #?       (write-buffered Stderr %eax)
13286 #?       (write-buffered Stderr "@")
13287 #?       (write-int32-hex-buffered Stderr %ebx)
13288 #?       (write-buffered Stderr " to ")
13289 #?       (write-int32-hex-buffered Stderr %edx)
13290 #?       (write-buffered Stderr Newline)
13291 #?       (flush Stderr)
13292       # v->offset = next-offset
13293       89/<- *(ebx+0x14) 2/r32/edx  # Var-offset
13294       # next-offset += size-of(v)
13295       (size-of %ebx)  # => eax
13296       01/add-to %edx 0/r32/eax
13297       # curr = lookup(curr->next)
13298       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
13299       89/<- %ecx 0/r32/eax
13300       #
13301       eb/jump loop/disp8
13302     }
13303 $populate-mu-type-offsets-in-inouts:end:
13304     # . restore registers
13305     5f/pop-to-edi
13306     5b/pop-to-ebx
13307     5a/pop-to-edx
13308     59/pop-to-ecx
13309     58/pop-to-eax
13310     # . epilogue
13311     89/<- %esp 5/r32/ebp
13312     5d/pop-to-ebp
13313     c3/return
13314 
13315 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)
13316     # . prologue
13317     55/push-ebp
13318     89/<- %ebp 4/r32/esp
13319     # . save registers
13320     50/push-eax
13321     51/push-ecx
13322     53/push-ebx
13323     56/push-esi
13324     # esi = stmts
13325     8b/-> *(ebp+0xc) 6/r32/esi
13326     #
13327     {
13328 $emit-subx-stmt-list:loop:
13329       81 7/subop/compare %esi 0/imm32
13330       0f 84/jump-if-= break/disp32
13331       # var curr-stmt/ecx: (addr stmt) = lookup(stmts->value)
13332       (lookup *esi *(esi+4))  # List-value List-value => eax
13333       89/<- %ecx 0/r32/eax
13334       {
13335 $emit-subx-stmt-list:check-for-block:
13336         81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
13337         75/jump-if-!= break/disp8
13338 $emit-subx-stmt-list:block:
13339         (emit-subx-block *(ebp+8) %ecx *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
13340       }
13341       {
13342 $emit-subx-stmt-list:check-for-stmt:
13343         81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
13344         0f 85/jump-if-!= break/disp32
13345 $emit-subx-stmt-list:stmt1:
13346         {
13347           (is-mu-branch? %ecx)  # => eax
13348           3d/compare-eax-and 0/imm32/false
13349           0f 84/jump-if-= break/disp32
13350 $emit-subx-stmt-list:branch-stmt:
13351 +-- 27 lines: # unconditional loops -----------------------------------------------------------------------------------------------------------------------------------------------------
13378 +-- 16 lines: # unconditional breaks ----------------------------------------------------------------------------------------------------------------------------------------------------
13394 +-- 38 lines: # simple conditional branches without a target ----------------------------------------------------------------------------------------------------------------------------
13432 +-- 19 lines: # conditional branches with an explicit target ----------------------------------------------------------------------------------------------------------------------------
13451         }
13452 $emit-subx-stmt-list:1-to-1:
13453         (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x18) *(ebp+0x1c))
13454         e9/jump $emit-subx-stmt-list:continue/disp32
13455       }
13456       {
13457 $emit-subx-stmt-list:check-for-var-def:
13458         81 7/subop/compare *ecx 2/imm32/var-def  # Stmt-tag
13459         75/jump-if-!= break/disp8
13460 $emit-subx-stmt-list:var-def:
13461         (emit-subx-var-def *(ebp+8) %ecx)
13462         (push *(ebp+0x10) *(ecx+4))  # Vardef-var
13463         (push *(ebp+0x10) *(ecx+8))  # Vardef-var
13464         (push *(ebp+0x10) 0)  # Live-var-register-spilled = 0 for vars on the stack
13465         #
13466         eb/jump $emit-subx-stmt-list:continue/disp8
13467       }
13468       {
13469 $emit-subx-stmt-list:check-for-reg-var-def:
13470         81 7/subop/compare *ecx 3/imm32/reg-var-def  # Stmt-tag
13471         0f 85/jump-if-!= break/disp32
13472 $emit-subx-stmt-list:reg-var-def:
13473         # TODO: ensure that there's exactly one output
13474         (push-output-and-maybe-emit-spill *(ebp+8) %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
13475         # emit the instruction as usual
13476         (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x18) *(ebp+0x1c))
13477         #
13478         eb/jump $emit-subx-stmt-list:continue/disp8
13479       }
13480 $emit-subx-stmt-list:continue:
13481       # TODO: raise an error on unrecognized Stmt-tag
13482       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
13483       89/<- %esi 0/r32/eax
13484       e9/jump loop/disp32
13485     }
13486 $emit-subx-stmt-list:emit-cleanup:
13487     (emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth)
13488 $emit-subx-stmt-list:clean-up:
13489     (clean-up-blocks *(ebp+0x10) *Curr-block-depth *(ebp+0x14))
13490 $emit-subx-stmt-list:end:
13491     # . restore registers
13492     5e/pop-to-esi
13493     5b/pop-to-ebx
13494     59/pop-to-ecx
13495     58/pop-to-eax
13496     # . epilogue
13497     89/<- %esp 5/r32/ebp
13498     5d/pop-to-ebp
13499     c3/return
13500 
13501 # 'later-stmts' includes 'stmt', but will behave the same even without it; reg-var-def stmts are guaranteed not to write to function outputs.
13502 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)
13503     # . prologue
13504     55/push-ebp
13505     89/<- %ebp 4/r32/esp
13506     # . save registers
13507     50/push-eax
13508     51/push-ecx
13509     52/push-edx
13510     # ecx = stmt
13511     8b/-> *(ebp+0xc) 1/r32/ecx
13512     # var sv/eax: (addr stmt-var) = lookup(curr-stmt->outputs)
13513     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
13514     # TODO: assert !sv->is-deref?
13515     # var v/ecx: (addr var) = lookup(sv->value)
13516     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13517     89/<- %ecx 0/r32/eax
13518     # v->block-depth = *Curr-block-depth
13519     8b/-> *Curr-block-depth 0/r32/eax
13520     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
13521 #?     (write-buffered Stderr "var ")
13522 #?     (lookup *ecx *(ecx+4))
13523 #?     (write-buffered Stderr %eax)
13524 #?     (write-buffered Stderr " at depth ")
13525 #?     (write-int32-hex-buffered Stderr *(ecx+0x10))
13526 #?     (write-buffered Stderr Newline)
13527 #?     (flush Stderr)
13528     # ensure that v is in a register
13529     81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
13530     0f 84/jump-if-= $push-output-and-maybe-emit-spill:abort/disp32
13531     # var emit-spill?/edx: boolean = not-yet-spilled-this-block? && will-not-write-some-register?(fn)
13532     (not-yet-spilled-this-block? %ecx *(ebp+0x10))  # => eax
13533     89/<- %edx 0/r32/eax
13534     3d/compare-eax-and 0/imm32/false
13535     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
13536     (will-not-write-some-register? %ecx *(ebp+0x14) *(ebp+0x18))  # => eax
13537     89/<- %edx 0/r32/eax
13538     # check emit-spill?
13539     3d/compare-eax-and 0/imm32/false
13540     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
13541     # TODO: assert(size-of(output) == 4)
13542     # *Curr-local-stack-offset -= 4
13543     81 5/subop/subtract *Curr-local-stack-offset 4/imm32
13544     # emit spill
13545     (emit-indent *(ebp+8) *Curr-block-depth)
13546     (write-buffered *(ebp+8) "ff 6/subop/push %")
13547     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
13548     (write-buffered *(ebp+8) %eax)
13549     (write-buffered *(ebp+8) Newline)
13550 $push-output-and-maybe-emit-spill:push:
13551     8b/-> *(ebp+0xc) 1/r32/ecx
13552     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
13553     # push(vars, {sv->value, emit-spill?})
13554     (push *(ebp+0x10) *eax)  # Stmt-var-value
13555     (push *(ebp+0x10) *(eax+4))  # Stmt-var-value
13556     (push *(ebp+0x10) %edx)
13557 $push-output-and-maybe-emit-spill:end:
13558     # . restore registers
13559     5a/pop-to-edx
13560     59/pop-to-ecx
13561     58/pop-to-eax
13562     # . epilogue
13563     89/<- %esp 5/r32/ebp
13564     5d/pop-to-ebp
13565     c3/return
13566 
13567 $push-output-and-maybe-emit-spill:abort:
13568     # error("var '" var->name "' initialized from an instruction must live in a register\n")
13569     (write-buffered *(ebp+0x1c) "var '")
13570     (write-buffered *(ebp+0x1c) *eax)  # Var-name
13571     (write-buffered *(ebp+0x1c) "' initialized from an instruction must live in a register\n")
13572     (flush *(ebp+0x1c))
13573     (stop *(ebp+0x20) 1)
13574     # never gets here
13575 
13576 emit-subx-cleanup-and-unconditional-nonlocal-branch:  # out: (addr buffered-file), stmt: (addr stmt1), vars: (addr stack live-var)
13577     # . prologue
13578     55/push-ebp
13579     89/<- %ebp 4/r32/esp
13580     # . save registers
13581     50/push-eax
13582     51/push-ecx
13583     # ecx = stmt
13584     8b/-> *(ebp+0xc) 1/r32/ecx
13585     # var target/eax: (addr array byte) = curr-stmt->inouts->value->name
13586     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13587     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13588     (lookup *eax *(eax+4))  # Var-name Var-name => eax
13589     # clean up until target block
13590     (emit-cleanup-code-until-target *(ebp+8) *(ebp+0x10) %eax)
13591     # emit jump to target block
13592     (emit-indent *(ebp+8) *Curr-block-depth)
13593     (write-buffered *(ebp+8) "e9/jump ")
13594     (write-buffered *(ebp+8) %eax)
13595     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
13596     (string-starts-with? %eax "break")
13597     3d/compare-eax-and 0/imm32/false
13598     {
13599       74/jump-if-= break/disp8
13600       (write-buffered *(ebp+8) ":break/disp32\n")
13601     }
13602     3d/compare-eax-and 0/imm32/false  # just in case the function call modified flags
13603     {
13604       75/jump-if-!= break/disp8
13605       (write-buffered *(ebp+8) ":loop/disp32\n")
13606     }
13607 $emit-subx-cleanup-and-unconditional-nonlocal-branch:end:
13608     # . restore registers
13609     59/pop-to-ecx
13610     58/pop-to-eax
13611     # . epilogue
13612     89/<- %esp 5/r32/ebp
13613     5d/pop-to-ebp
13614     c3/return
13615 
13616 is-mu-branch?:  # stmt: (addr stmt1) -> result/eax: boolean
13617     # . prologue
13618     55/push-ebp
13619     89/<- %ebp 4/r32/esp
13620     # . save registers
13621     51/push-ecx
13622     # ecx = lookup(stmt->operation)
13623     8b/-> *(ebp+8) 1/r32/ecx
13624     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
13625     89/<- %ecx 0/r32/eax
13626     # if (stmt->operation starts with "loop") return true
13627     (string-starts-with? %ecx "loop")  # => eax
13628     3d/compare-eax-and 0/imm32/false
13629     75/jump-if-not-equal $is-mu-branch?:end/disp8
13630     # otherwise return (stmt->operation starts with "break")
13631     (string-starts-with? %ecx "break")  # => eax
13632 $is-mu-branch?:end:
13633     # . restore registers
13634     59/pop-to-ecx
13635     # . epilogue
13636     89/<- %esp 5/r32/ebp
13637     5d/pop-to-ebp
13638     c3/return
13639 
13640 emit-reverse-break:  # out: (addr buffered-file), stmt: (addr stmt1)
13641     # . prologue
13642     55/push-ebp
13643     89/<- %ebp 4/r32/esp
13644     # . save registers
13645     50/push-eax
13646     # eax = stmt
13647     8b/-> *(ebp+0xc) 0/r32/eax
13648     #
13649     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
13650     (get Reverse-branch %eax 0x10 "reverse-branch: ")  # => eax: (addr handle array byte)
13651     (emit-indent *(ebp+8) *Curr-block-depth)
13652     (lookup *eax *(eax+4))  # => eax
13653     (write-buffered *(ebp+8) %eax)
13654     (write-buffered *(ebp+8) " break/disp32\n")
13655 $emit-reverse-break:end:
13656     # . restore registers
13657     58/pop-to-eax
13658     # . epilogue
13659     89/<- %esp 5/r32/ebp
13660     5d/pop-to-ebp
13661     c3/return
13662 
13663 == data
13664 
13665 # Table from Mu branch instructions to the reverse SubX opcodes for them.
13666 Reverse-branch:  # (table (handle array byte) (handle array byte))
13667   # a table is a stream
13668   0x140/imm32/write
13669   0/imm32/read
13670   0x140/imm32/size
13671   # data
13672   0x11/imm32/alloc-id   _string-break-if-=/imm32                0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
13673   0x11/imm32/alloc-id   _string-loop-if-=/imm32                 0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
13674   0x11/imm32/alloc-id   _string-break-if-!=/imm32               0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
13675   0x11/imm32/alloc-id   _string-loop-if-!=/imm32                0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
13676   0x11/imm32/alloc-id   _string-break-if-</imm32                0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
13677   0x11/imm32/alloc-id   _string-loop-if-</imm32                 0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
13678   0x11/imm32/alloc-id   _string-break-if->/imm32                0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
13679   0x11/imm32/alloc-id   _string-loop-if->/imm32                 0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
13680   0x11/imm32/alloc-id   _string-break-if-<=/imm32               0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
13681   0x11/imm32/alloc-id   _string-loop-if-<=/imm32                0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
13682   0x11/imm32/alloc-id   _string-break-if->=/imm32               0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
13683   0x11/imm32/alloc-id   _string-loop-if->=/imm32                0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
13684   0x11/imm32/alloc-id   _string-break-if-addr</imm32            0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
13685   0x11/imm32/alloc-id   _string-loop-if-addr</imm32             0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
13686   0x11/imm32/alloc-id   _string-break-if-addr>/imm32            0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
13687   0x11/imm32/alloc-id   _string-loop-if-addr>/imm32             0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
13688   0x11/imm32/alloc-id   _string-break-if-addr<=/imm32           0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
13689   0x11/imm32/alloc-id   _string-loop-if-addr<=/imm32            0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
13690   0x11/imm32/alloc-id   _string-break-if-addr>=/imm32           0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
13691   0x11/imm32/alloc-id   _string-loop-if-addr>=/imm32            0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
13692 
13693 == code
13694 
13695 emit-unconditional-jump-to-depth:  # out: (addr buffered-file), vars: (addr stack live-var), depth: int, label-suffix: (addr array byte)
13696     # . prologue
13697     55/push-ebp
13698     89/<- %ebp 4/r32/esp
13699     # . save registers
13700     50/push-eax
13701     51/push-ecx
13702     52/push-edx
13703     53/push-ebx
13704     56/push-esi
13705     # ecx = vars
13706     8b/-> *(ebp+0xc) 1/r32/ecx
13707     # var eax: int = vars->top
13708     8b/-> *ecx 0/r32/eax
13709     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
13710     8d/copy-address *(ecx+eax-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
13711     # var min/ecx: (addr handle var) = vars->data
13712     8d/copy-address *(ecx+8) 1/r32/ecx
13713     # edx = depth
13714     8b/-> *(ebp+0x10) 2/r32/edx
13715     {
13716 $emit-unconditional-jump-to-depth:loop:
13717       # if (curr < min) break
13718       39/compare %esi 1/r32/ecx
13719       0f 82/jump-if-addr< break/disp32
13720       # var v/ebx: (addr var) = lookup(*curr)
13721       (lookup *esi *(esi+4))  # => eax
13722       89/<- %ebx 0/r32/eax
13723       # if (v->block-depth < until-block-depth) break
13724       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
13725       0f 8c/jump-if-< break/disp32
13726       {
13727 $emit-unconditional-jump-to-depth:check:
13728         # if v->block-depth != until-block-depth, continue
13729         39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
13730         0f 85/jump-if-!= break/disp32
13731 $emit-unconditional-jump-to-depth:depth-found:
13732         # if v is not a literal, continue
13733         (size-of %ebx)  # => eax
13734         3d/compare-eax-and 0/imm32
13735         0f 85/jump-if-!= break/disp32
13736 $emit-unconditional-jump-to-depth:label-found:
13737         # emit unconditional jump, then return
13738         (emit-indent *(ebp+8) *Curr-block-depth)
13739         (write-buffered *(ebp+8) "e9/jump ")
13740         (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
13741         (write-buffered *(ebp+8) %eax)
13742         (write-buffered *(ebp+8) ":")
13743         (write-buffered *(ebp+8) *(ebp+0x14))
13744         (write-buffered *(ebp+8) "/disp32\n")
13745         eb/jump $emit-unconditional-jump-to-depth:end/disp8
13746       }
13747       # curr -= 12
13748       81 5/subop/subtract %esi 0xc/imm32
13749       e9/jump loop/disp32
13750     }
13751     # TODO: error if no label at 'depth' was found
13752 $emit-unconditional-jump-to-depth:end:
13753     # . restore registers
13754     5e/pop-to-esi
13755     5b/pop-to-ebx
13756     5a/pop-to-edx
13757     59/pop-to-ecx
13758     58/pop-to-eax
13759     # . epilogue
13760     89/<- %esp 5/r32/ebp
13761     5d/pop-to-ebp
13762     c3/return
13763 
13764 # emit clean-up code for 'vars' until some block depth
13765 # doesn't actually modify 'vars' so we need traverse manually inside the stack
13766 emit-cleanup-code-until-depth:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-depth: int
13767     # . prologue
13768     55/push-ebp
13769     89/<- %ebp 4/r32/esp
13770     # . save registers
13771     50/push-eax
13772     51/push-ecx
13773     52/push-edx
13774     53/push-ebx
13775     56/push-esi
13776 #?     (write-buffered Stderr "--- cleanup\n")
13777 #?     (flush Stderr)
13778     # ecx = vars
13779     8b/-> *(ebp+0xc) 1/r32/ecx
13780     # var esi: int = vars->top
13781     8b/-> *ecx 6/r32/esi
13782     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
13783     8d/copy-address *(ecx+esi-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
13784     # var min/ecx: (addr handle var) = vars->data
13785     81 0/subop/add %ecx 8/imm32
13786     # edx = until-block-depth
13787     8b/-> *(ebp+0x10) 2/r32/edx
13788     {
13789 $emit-cleanup-code-until-depth:loop:
13790       # if (curr < min) break
13791       39/compare %esi 1/r32/ecx
13792       0f 82/jump-if-addr< break/disp32
13793       # var v/ebx: (addr var) = lookup(*curr)
13794       (lookup *esi *(esi+4))  # => eax
13795       89/<- %ebx 0/r32/eax
13796 #?       (lookup *ebx *(ebx+4))  # Var-name
13797 #?       (write-buffered Stderr "var ")
13798 #?       (write-buffered Stderr %eax)
13799 #?       (write-buffered Stderr Newline)
13800 #?       (flush Stderr)
13801       # if (v->block-depth < until-block-depth) break
13802       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
13803       0f 8c/jump-if-< break/disp32
13804       # if v is in a register
13805       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
13806       {
13807         0f 84/jump-if-= break/disp32
13808         {
13809 $emit-cleanup-code-until-depth:check-for-previous-spill:
13810           8b/-> *(esi+8) 0/r32/eax  # Live-var-register-spilled
13811           3d/compare-eax-and 0/imm32/false
13812           74/jump-if-= break/disp8
13813 $emit-cleanup-code-until-depth:reclaim-var-in-register:
13814           (emit-indent *(ebp+8) *Curr-block-depth)
13815           (write-buffered *(ebp+8) "8f 0/subop/pop %")
13816           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
13817           (write-buffered *(ebp+8) %eax)
13818           (write-buffered *(ebp+8) Newline)
13819         }
13820         eb/jump $emit-cleanup-code-until-depth:continue/disp8
13821       }
13822       # otherwise v is on the stack
13823       {
13824         75/jump-if-!= break/disp8
13825 $emit-cleanup-code-until-depth:var-on-stack:
13826         (size-of %ebx)  # => eax
13827         # don't emit code for labels
13828         3d/compare-eax-and 0/imm32
13829         74/jump-if-= break/disp8
13830 $emit-cleanup-code-until-depth:reclaim-var-on-stack:
13831         (emit-indent *(ebp+8) *Curr-block-depth)
13832         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
13833         (write-int32-hex-buffered *(ebp+8) %eax)
13834         (write-buffered *(ebp+8) "/imm32\n")
13835       }
13836 $emit-cleanup-code-until-depth:continue:
13837       # curr -= 12
13838       81 5/subop/subtract %esi 0xc/imm32
13839       e9/jump loop/disp32
13840     }
13841 $emit-cleanup-code-until-depth:end:
13842     # . restore registers
13843     5e/pop-to-esi
13844     5b/pop-to-ebx
13845     5a/pop-to-edx
13846     59/pop-to-ecx
13847     58/pop-to-eax
13848     # . epilogue
13849     89/<- %esp 5/r32/ebp
13850     5d/pop-to-ebp
13851     c3/return
13852 
13853 # emit clean-up code for 'vars' until a given label is encountered
13854 # doesn't actually modify 'vars' so we need traverse manually inside the stack
13855 emit-cleanup-code-until-target:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-label: (addr array byte)
13856     # . prologue
13857     55/push-ebp
13858     89/<- %ebp 4/r32/esp
13859     # . save registers
13860     50/push-eax
13861     51/push-ecx
13862     52/push-edx
13863     53/push-ebx
13864     # ecx = vars
13865     8b/-> *(ebp+0xc) 1/r32/ecx
13866     # var eax: int = vars->top
13867     8b/-> *ecx 0/r32/eax
13868     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
13869     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
13870     # var min/ecx: (addr handle var) = vars->data
13871     81 0/subop/add %ecx 8/imm32
13872     {
13873 $emit-cleanup-code-until-target:loop:
13874       # if (curr < min) break
13875       39/compare %edx 1/r32/ecx
13876       0f 82/jump-if-addr< break/disp32
13877       # var v/ebx: (handle var) = lookup(*curr)
13878       (lookup *edx *(edx+4))  # => eax
13879       89/<- %ebx 0/r32/eax
13880       # if (v->name == until-block-label) break
13881       (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
13882       (string-equal? %eax *(ebp+0x10))  # => eax
13883       3d/compare-eax-and 0/imm32/false
13884       0f 85/jump-if-!= break/disp32
13885       # if v is in a register
13886       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
13887       {
13888         0f 84/jump-if-= break/disp32
13889         {
13890 $emit-cleanup-code-until-target:check-for-previous-spill:
13891           8b/-> *(edx+8) 0/r32/eax  # Live-var-register-spilled
13892           3d/compare-eax-and 0/imm32/false
13893           74/jump-if-= break/disp8
13894 $emit-cleanup-code-until-target:reclaim-var-in-register:
13895           (emit-indent *(ebp+8) *Curr-block-depth)
13896           (write-buffered *(ebp+8) "8f 0/subop/pop %")
13897           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
13898           (write-buffered *(ebp+8) %eax)
13899           (write-buffered *(ebp+8) Newline)
13900         }
13901         eb/jump $emit-cleanup-code-until-target:continue/disp8
13902       }
13903       # otherwise v is on the stack
13904       {
13905         75/jump-if-!= break/disp8
13906 $emit-cleanup-code-until-target:reclaim-var-on-stack:
13907         (size-of %ebx)  # => eax
13908         # don't emit code for labels
13909         3d/compare-eax-and 0/imm32
13910         74/jump-if-= break/disp8
13911         #
13912         (emit-indent *(ebp+8) *Curr-block-depth)
13913         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
13914         (write-int32-hex-buffered *(ebp+8) %eax)
13915         (write-buffered *(ebp+8) "/imm32\n")
13916       }
13917 $emit-cleanup-code-until-target:continue:
13918       # curr -= 12
13919       81 5/subop/subtract %edx 0xc/imm32
13920       e9/jump loop/disp32
13921     }
13922 $emit-cleanup-code-until-target:end:
13923     # . restore registers
13924     5b/pop-to-ebx
13925     5a/pop-to-edx
13926     59/pop-to-ecx
13927     58/pop-to-eax
13928     # . epilogue
13929     89/<- %esp 5/r32/ebp
13930     5d/pop-to-ebp
13931     c3/return
13932 
13933 # Return true if there isn't a variable in 'vars' with the same block-depth
13934 # and register as 'v'.
13935 # 'v' is guaranteed not to be within 'vars'.
13936 not-yet-spilled-this-block?:  # v: (addr var), vars: (addr stack live-var) -> result/eax: boolean
13937     # . prologue
13938     55/push-ebp
13939     89/<- %ebp 4/r32/esp
13940     # . save registers
13941     51/push-ecx
13942     52/push-edx
13943     53/push-ebx
13944     56/push-esi
13945     57/push-edi
13946     # ecx = vars
13947     8b/-> *(ebp+0xc) 1/r32/ecx
13948     # var eax: int = vars->top
13949     8b/-> *ecx 0/r32/eax
13950     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
13951     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
13952     # var min/ecx: (addr handle var) = vars->data
13953     8d/copy-address *(ecx+8) 1/r32/ecx
13954     # var depth/ebx: int = v->block-depth
13955     8b/-> *(ebp+8) 3/r32/ebx
13956     8b/-> *(ebx+0x10) 3/r32/ebx  # Var-block-depth
13957     # var needle/esi: (addr array byte) = v->register
13958     8b/-> *(ebp+8) 6/r32/esi
13959     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
13960     89/<- %esi 0/r32/eax
13961     {
13962 $not-yet-spilled-this-block?:loop:
13963       # if (curr < min) break
13964       39/compare %edx 1/r32/ecx
13965       0f 82/jump-if-addr< break/disp32
13966       # var cand/edi: (addr var) = lookup(*curr)
13967       (lookup *edx *(edx+4))  # => eax
13968       89/<- %edi 0/r32/eax
13969       # if (cand->block-depth < depth) break
13970       39/compare *(edi+0x10) 3/r32/ebx  # Var-block-depth
13971       0f 8c/jump-if-< break/disp32
13972       # var cand-reg/edi: (array array byte) = cand->reg
13973       (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
13974       89/<- %edi 0/r32/eax
13975       # if (cand-reg == null) continue
13976       {
13977 $not-yet-spilled-this-block?:check-reg:
13978         81 7/subop/compare %edi 0/imm32
13979         0f 84/jump-if-= break/disp32
13980         # if (cand-reg == needle) return true
13981         (string-equal? %esi %edi)  # => eax
13982         3d/compare-eax-and 0/imm32/false
13983         74/jump-if-= break/disp8
13984 $not-yet-spilled-this-block?:return-false:
13985         b8/copy-to-eax 0/imm32/false
13986         eb/jump $not-yet-spilled-this-block?:end/disp8
13987       }
13988 $not-yet-spilled-this-block?:continue:
13989       # curr -= 12
13990       81 5/subop/subtract %edx 0xc/imm32
13991       e9/jump loop/disp32
13992     }
13993 $not-yet-spilled-this-block?:return-true:
13994     # return true
13995     b8/copy-to-eax 1/imm32/true
13996 $not-yet-spilled-this-block?:end:
13997     # . restore registers
13998     5f/pop-to-edi
13999     5e/pop-to-esi
14000     5b/pop-to-ebx
14001     5a/pop-to-edx
14002     59/pop-to-ecx
14003     # . epilogue
14004     89/<- %esp 5/r32/ebp
14005     5d/pop-to-ebp
14006     c3/return
14007 
14008 # could the register of 'v' ever be written to by one of the vars in fn-outputs?
14009 will-not-write-some-register?:  # v: (addr var), stmts: (addr list stmt), fn: (addr function) -> result/eax: boolean
14010     # . prologue
14011     55/push-ebp
14012     89/<- %ebp 4/r32/esp
14013     # eax = v
14014     8b/-> *(ebp+8) 0/r32/eax
14015     # var reg/eax: (addr array byte) = lookup(v->register)
14016     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
14017     # var target/eax: (addr var) = find-register(fn-outputs, reg)
14018     (find-register *(ebp+0x10) %eax)  # => eax
14019     # if (target == 0) return true
14020     {
14021       3d/compare-eax-and 0/imm32
14022       75/jump-if-!= break/disp8
14023       b8/copy-to-eax 1/imm32/true
14024       eb/jump $will-not-write-some-register?:end/disp8
14025     }
14026     # return !assigns-in-stmts?(stmts, target)
14027     (assigns-in-stmts? *(ebp+0xc) %eax)  # => eax
14028     3d/compare-eax-and 0/imm32/false
14029     # assume: true = 1, so no need to mask with 0x000000ff
14030     0f 94/set-if-= %al
14031 $will-not-write-some-register?:end:
14032     # . epilogue
14033     89/<- %esp 5/r32/ebp
14034     5d/pop-to-ebp
14035     c3/return
14036 
14037 # return fn output with matching register
14038 # always returns false if 'reg' is null
14039 find-register:  # fn: (addr function), reg: (addr array byte) -> result/eax: (addr var)
14040     # . prologue
14041     55/push-ebp
14042     89/<- %ebp 4/r32/esp
14043     # . save registers
14044     51/push-ecx
14045     # var curr/ecx: (addr list var) = lookup(fn->outputs)
14046     8b/-> *(ebp+8) 1/r32/ecx
14047     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
14048     89/<- %ecx 0/r32/eax
14049     {
14050 $find-register:loop:
14051       # if (curr == 0) break
14052       81 7/subop/compare %ecx 0/imm32
14053       74/jump-if-= break/disp8
14054       # eax = curr->value->register
14055       (lookup *ecx *(ecx+4))  # List-value List-value => eax
14056       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
14057       # if (eax == reg) return curr->value
14058 $find-register:compare:
14059       (string-equal? *(ebp+0xc) %eax)  # => eax
14060       {
14061         3d/compare-eax-and 0/imm32/false
14062         74/jump-if-= break/disp8
14063 $find-register:found:
14064         (lookup *ecx *(ecx+4))  # List-value List-value => eax
14065         eb/jump $find-register:end/disp8
14066       }
14067       # curr = lookup(curr->next)
14068       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
14069       89/<- %ecx 0/r32/eax
14070       #
14071       eb/jump loop/disp8
14072     }
14073 $find-register:end:
14074     # . restore registers
14075     59/pop-to-ecx
14076     # . epilogue
14077     89/<- %esp 5/r32/ebp
14078     5d/pop-to-ebp
14079     c3/return
14080 
14081 assigns-in-stmts?:  # stmts: (addr list stmt), v: (addr var) -> result/eax: boolean
14082     # . prologue
14083     55/push-ebp
14084     89/<- %ebp 4/r32/esp
14085     # . save registers
14086     51/push-ecx
14087     # var curr/ecx: (addr list stmt) = stmts
14088     8b/-> *(ebp+8) 1/r32/ecx
14089     {
14090       # if (curr == 0) break
14091       81 7/subop/compare %ecx 0/imm32
14092       74/jump-if-= break/disp8
14093       # if assigns-in-stmt?(curr->value, v) return true
14094       (lookup *ecx *(ecx+4))  # List-value List-value => eax
14095       (assigns-in-stmt? %eax *(ebp+0xc))  # => eax
14096       3d/compare-eax-and 0/imm32/false
14097       75/jump-if-!= break/disp8
14098       # curr = lookup(curr->next)
14099       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
14100       89/<- %ecx 0/r32/eax
14101       #
14102       eb/jump loop/disp8
14103     }
14104 $assigns-in-stmts?:end:
14105     # . restore registers
14106     59/pop-to-ecx
14107     # . epilogue
14108     89/<- %esp 5/r32/ebp
14109     5d/pop-to-ebp
14110     c3/return
14111 
14112 assigns-in-stmt?:  # stmt: (addr stmt), v: (addr var) -> result/eax: boolean
14113     # . prologue
14114     55/push-ebp
14115     89/<- %ebp 4/r32/esp
14116     # . save registers
14117     51/push-ecx
14118     # ecx = stmt
14119     8b/-> *(ebp+8) 1/r32/ecx
14120     # if stmt is a stmt1, return assigns-in-stmt-vars?(stmt->outputs, v)
14121     {
14122       81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
14123       75/jump-if-!= break/disp8
14124       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
14125       (assigns-in-stmt-vars? %eax *(ebp+0xc))  # => eax
14126       eb/jump $assigns-in-stmt?:end/disp8
14127     }
14128     # if stmt is a block, return assigns-in-stmts?(stmt->stmts, v)
14129     {
14130       81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
14131       75/jump-if-!= break/disp8
14132       (lookup *(ecx+4) *(ecx+8))  # Block-stmts Block-stmts => eax
14133       (assigns-in-stmts? %eax *(ebp+0xc))  # => eax
14134       eb/jump $assigns-in-stmt?:end/disp8
14135     }
14136     # otherwise return false
14137     b8/copy 0/imm32/false
14138 $assigns-in-stmt?:end:
14139     # . restore registers
14140     59/pop-to-ecx
14141     # . epilogue
14142     89/<- %esp 5/r32/ebp
14143     5d/pop-to-ebp
14144     c3/return
14145 
14146 assigns-in-stmt-vars?:  # stmt-var: (addr stmt-var), v: (addr var) -> result/eax: boolean
14147     # . prologue
14148     55/push-ebp
14149     89/<- %ebp 4/r32/esp
14150     # . save registers
14151     51/push-ecx
14152     # var curr/ecx: (addr stmt-var) = stmt-var
14153     8b/-> *(ebp+8) 1/r32/ecx
14154     {
14155       # if (curr == 0) break
14156       81 7/subop/compare %ecx 0/imm32
14157       74/jump-if-= break/disp8
14158       # eax = lookup(curr->value)
14159       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
14160       # if (eax == v  &&  curr->is-deref? == false) return true
14161       {
14162         39/compare *(ebp+0xc) 0/r32/eax
14163         75/jump-if-!= break/disp8
14164         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
14165         75/jump-if-!= break/disp8
14166         b8/copy-to-eax 1/imm32/true
14167         eb/jump $assigns-in-stmt-vars?:end/disp8
14168       }
14169       # curr = lookup(curr->next)
14170       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
14171       89/<- %ecx 0/r32/eax
14172       #
14173       eb/jump loop/disp8
14174     }
14175 $assigns-in-stmt-vars?:end:
14176     # . restore registers
14177     59/pop-to-ecx
14178     # . epilogue
14179     89/<- %esp 5/r32/ebp
14180     5d/pop-to-ebp
14181     c3/return
14182 
14183 # is there a var before 'v' with the same block-depth and register on the 'vars' stack?
14184 # v is guaranteed to be within vars
14185 # 'start' is provided as an optimization, a pointer within vars
14186 # *start == v
14187 same-register-spilled-before?:  # v: (addr var), vars: (addr stack (handle var)), start: (addr var) -> result/eax: boolean
14188     # . prologue
14189     55/push-ebp
14190     89/<- %ebp 4/r32/esp
14191     # . save registers
14192     51/push-ecx
14193     52/push-edx
14194     53/push-ebx
14195     56/push-esi
14196     57/push-edi
14197     # ecx = v
14198     8b/-> *(ebp+8) 1/r32/ecx
14199     # var reg/edx: (addr array byte) = lookup(v->register)
14200     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
14201     89/<- %edx 0/r32/eax
14202     # var depth/ebx: int = v->block-depth
14203     8b/-> *(ecx+0x10) 3/r32/ebx  # Var-block-depth
14204     # var min/ecx: (addr handle var) = vars->data
14205     8b/-> *(ebp+0xc) 1/r32/ecx
14206     81 0/subop/add %ecx 8/imm32
14207     # TODO: check that start >= min and start < &vars->data[top]
14208     # TODO: check that *start == v
14209     # var curr/esi: (addr handle var) = start
14210     8b/-> *(ebp+0x10) 6/r32/esi
14211     # curr -= 8
14212     81 5/subop/subtract %esi 8/imm32
14213     {
14214 $same-register-spilled-before?:loop:
14215       # if (curr < min) break
14216       39/compare %esi 1/r32/ecx
14217       0f 82/jump-if-addr< break/disp32
14218       # var x/eax: (addr var) = lookup(*curr)
14219       (lookup *esi *(esi+4))  # => eax
14220       # if (x->block-depth < depth) break
14221       39/compare *(eax+0x10) 3/r32/ebx  # Var-block-depth
14222       0f 8c/jump-if-< break/disp32
14223       # if (x->register == 0) continue
14224       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
14225       74/jump-if-= $same-register-spilled-before?:continue/disp8
14226       # if (x->register == reg) return true
14227       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
14228       (string-equal? %eax %edx)  # => eax
14229       3d/compare-eax-and 0/imm32/false
14230       b8/copy-to-eax 1/imm32/true
14231       75/jump-if-!= $same-register-spilled-before?:end/disp8
14232 $same-register-spilled-before?:continue:
14233       # curr -= 8
14234       81 5/subop/subtract %esi 8/imm32
14235       e9/jump loop/disp32
14236     }
14237 $same-register-spilled-before?:false:
14238     b8/copy-to-eax 0/imm32/false
14239 $same-register-spilled-before?:end:
14240     # . restore registers
14241     5f/pop-to-edi
14242     5e/pop-to-esi
14243     5b/pop-to-ebx
14244     5a/pop-to-edx
14245     59/pop-to-ecx
14246     # . epilogue
14247     89/<- %esp 5/r32/ebp
14248     5d/pop-to-ebp
14249     c3/return
14250 
14251 # Clean up global state for 'vars' until some block depth (inclusive).
14252 #
14253 # This would be a simple series of pops, if it wasn't for fn outputs, which
14254 # can occur anywhere in the stack.
14255 # So we have to _compact_ the entire array underlying the stack.
14256 #
14257 # We want to allow a fn output register to be written to by locals before the
14258 # output is set.
14259 # So fn outputs can't just be pushed at the start of the function.
14260 #
14261 # We want to allow other locals to shadow a fn output register after the
14262 # output is set.
14263 # So the output can't just always override anything in the stack. Sequence matters.
14264 clean-up-blocks:  # vars: (addr stack live-var), until-block-depth: int, fn: (addr function)
14265     # pseudocode:
14266     #   to = vars->top  (which points outside the stack)
14267     #   while true
14268     #     if to <= 0
14269     #       break
14270     #     var v = vars->data[to-1]
14271     #     if v.depth < until and !in-function-outputs?(fn, v)
14272     #       break
14273     #     --to
14274     #   from = to
14275     #   while true
14276     #     if from >= vars->top
14277     #       break
14278     #     assert(from >= to)
14279     #     v = vars->data[from]
14280     #     if in-function-outputs?(fn, v)
14281     #       if from > to
14282     #         vars->data[to] = vars->data[from]
14283     #       ++to
14284     #     ++from
14285     #   vars->top = to
14286     #
14287     # . prologue
14288     55/push-ebp
14289     89/<- %ebp 4/r32/esp
14290     # . save registers
14291     50/push-eax
14292     52/push-edx
14293     53/push-ebx
14294     56/push-esi
14295     57/push-edi
14296     # ebx = vars
14297     8b/-> *(ebp+8) 3/r32/ebx
14298     # edx = until-block-depth
14299     8b/-> *(ebp+0xc) 2/r32/edx
14300 $clean-up-blocks:phase1:
14301     # var to/edi: int = vars->top
14302     8b/-> *ebx 7/r32/edi
14303     {
14304 $clean-up-blocks:loop1:
14305       # if (to <= 0) break
14306       81 7/subop/compare %edi 0/imm32
14307       7e/jump-if-<= break/disp8
14308       # var v/eax: (addr var) = lookup(vars->data[to-1]->var)
14309       8d/copy-address *(ebx+edi-4) 0/r32/eax  # vars + 8 + to - 12
14310       (lookup *eax *(eax+4))  # => eax
14311       # if (v->block-depth >= until-block-depth) continue
14312       39/compare *(eax+0x10) 2/r32/edx  # Var-block-depth
14313       {
14314         7d/jump-if->= break/disp8
14315         # if (!in-function-outputs?(fn, v)) break
14316         (in-function-outputs? *(ebp+0x10) %eax)  # => eax
14317         3d/compare-eax-and 0/imm32/false
14318         74/jump-if-= $clean-up-blocks:phase2/disp8
14319       }
14320 $clean-up-blocks:loop1-continue:
14321       # --to
14322       81 5/subop/subtract %edi 0xc/imm32
14323       #
14324       eb/jump loop/disp8
14325     }
14326 $clean-up-blocks:phase2:
14327     # var from/esi: int = to
14328     89/<- %esi 7/r32/edi
14329     {
14330 $clean-up-blocks:loop2:
14331       # if (from >= vars->top) break
14332       3b/compare 6/r32/esi *ebx
14333       7d/jump-if->= break/disp8
14334       # var v/eax: (addr var) = lookup(vars->data[from]->var)
14335       8d/copy-address *(ebx+esi+8) 0/r32/eax
14336       (lookup *eax *(eax+4))  # => eax
14337       # if !in-function-outputs?(fn, v) continue
14338       (in-function-outputs? *(ebp+0x10) %eax)  # => eax
14339       3d/compare-eax-and 0/imm32/false
14340       74/jump-if-= $clean-up-blocks:loop2-continue/disp8
14341       # invariant: from >= to
14342       # if (from > to) vars->data[to] = vars->data[from]
14343       {
14344         39/compare %esi 7/r32/edi
14345         7e/jump-if-<= break/disp8
14346         56/push-esi
14347         57/push-edi
14348         # . var from/esi: (addr byte) = &vars->data[from]
14349         8d/copy-address *(ebx+esi+8) 6/r32/esi
14350         # . var to/edi: (addr byte) = &vars->data[to]
14351         8d/copy-address *(ebx+edi+8) 7/r32/edi
14352         # .
14353         8b/-> *esi 0/r32/eax
14354         89/<- *edi 0/r32/eax
14355         8b/-> *(esi+4) 0/r32/eax
14356         89/<- *(edi+4) 0/r32/eax
14357         8b/-> *(esi+8) 0/r32/eax
14358         89/<- *(edi+8) 0/r32/eax
14359         5f/pop-to-edi
14360         5e/pop-to-esi
14361       }
14362       # ++to
14363       81 0/subop/add %edi 0xc/imm32
14364 $clean-up-blocks:loop2-continue:
14365       # ++from
14366       81 0/subop/add %esi 0xc/imm32
14367       #
14368       eb/jump loop/disp8
14369     }
14370     89/<- *ebx 7/r32/edi
14371 $clean-up-blocks:end:
14372     # . restore registers
14373     5f/pop-to-edi
14374     5e/pop-to-esi
14375     5b/pop-to-ebx
14376     5a/pop-to-edx
14377     58/pop-to-eax
14378     # . epilogue
14379     89/<- %esp 5/r32/ebp
14380     5d/pop-to-ebp
14381     c3/return
14382 
14383 in-function-outputs?:  # fn: (addr function), target: (addr var) -> result/eax: boolean
14384     # . prologue
14385     55/push-ebp
14386     89/<- %ebp 4/r32/esp
14387     # . save registers
14388     51/push-ecx
14389     # var curr/ecx: (addr list var) = lookup(fn->outputs)
14390     8b/-> *(ebp+8) 1/r32/ecx
14391     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
14392     89/<- %ecx 0/r32/eax
14393     # while curr != null
14394     {
14395       81 7/subop/compare %ecx 0/imm32
14396       74/jump-if-= break/disp8
14397       # var v/eax: (addr var) = lookup(curr->value)
14398       (lookup *ecx *(ecx+4))  # List-value List-value => eax
14399       # if (v == target) return true
14400       39/compare *(ebp+0xc) 0/r32/eax
14401       b8/copy-to-eax 1/imm32/true
14402       74/jump-if-= $in-function-outputs?:end/disp8
14403       # curr = curr->next
14404       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
14405       89/<- %ecx 0/r32/eax
14406       #
14407       eb/jump loop/disp8
14408     }
14409     b8/copy-to-eax 0/imm32
14410 $in-function-outputs?:end:
14411     # . restore registers
14412     59/pop-to-ecx
14413     # . epilogue
14414     89/<- %esp 5/r32/ebp
14415     5d/pop-to-ebp
14416     c3/return
14417 
14418 emit-subx-var-def:  # out: (addr buffered-file), stmt: (addr stmt)
14419     # . prologue
14420     55/push-ebp
14421     89/<- %ebp 4/r32/esp
14422     # . save registers
14423     50/push-eax
14424     51/push-ecx
14425     52/push-edx
14426     # eax = stmt
14427     8b/-> *(ebp+0xc) 0/r32/eax
14428     # var v/ecx: (addr var)
14429     (lookup *(eax+4) *(eax+8))  # Vardef-var Vardef-var => eax
14430     89/<- %ecx 0/r32/eax
14431     # v->block-depth = *Curr-block-depth
14432     8b/-> *Curr-block-depth 0/r32/eax
14433     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
14434     # var n/edx: int = size-of(stmt->var)
14435     (size-of %ecx)  # => eax
14436     89/<- %edx 0/r32/eax
14437     # *Curr-local-stack-offset -= n
14438     29/subtract-from *Curr-local-stack-offset 2/r32/edx
14439     # v->offset = *Curr-local-stack-offset
14440     8b/-> *Curr-local-stack-offset 0/r32/eax
14441     89/<- *(ecx+0x14) 0/r32/eax  # Var-offset
14442     # if v is an array, do something special to initialize it
14443     {
14444       (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
14445       (is-mu-array? %eax)  # => eax
14446       3d/compare-eax-and 0/imm32/false
14447       0f 84/jump-if-= break/disp32
14448       # var array-size-without-size/edx: int = n-4
14449       81 5/subop/subtract %edx 4/imm32
14450       #
14451       (emit-array-data-initialization *(ebp+8) %edx)
14452       e9/jump $emit-subx-var-def:end/disp32
14453     }
14454     # another special-case for initializing streams
14455     # a stream is an array with 2 extra pointers
14456     {
14457       (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
14458       (is-mu-stream? %eax)  # => eax
14459       3d/compare-eax-and 0/imm32/false
14460       0f 84/jump-if-= break/disp32
14461       # var array-size-without-size/edx: int = n-12
14462       81 5/subop/subtract %edx 0xc/imm32
14463       (emit-array-data-initialization *(ebp+8) %edx)
14464       # emit read and write pointers
14465       (emit-indent *(ebp+8) *Curr-block-depth)
14466       (write-buffered *(ebp+8) "68/push 0/imm32\n")
14467       (emit-indent *(ebp+8) *Curr-block-depth)
14468       (write-buffered *(ebp+8) "68/push 0/imm32\n")
14469       #
14470       eb/jump $emit-subx-var-def:end/disp8
14471     }
14472     # while n > 0
14473     {
14474       81 7/subop/compare %edx 0/imm32
14475       7e/jump-if-<= break/disp8
14476       (emit-indent *(ebp+8) *Curr-block-depth)
14477       (write-buffered *(ebp+8) "68/push 0/imm32\n")
14478       # n -= 4
14479       81 5/subop/subtract %edx 4/imm32
14480       #
14481       eb/jump loop/disp8
14482     }
14483 $emit-subx-var-def:end:
14484     # . restore registers
14485     5a/pop-to-edx
14486     59/pop-to-ecx
14487     58/pop-to-eax
14488     # . epilogue
14489     89/<- %esp 5/r32/ebp
14490     5d/pop-to-ebp
14491     c3/return
14492 
14493 emit-array-data-initialization:  # out: (addr buffered-file), n: int
14494     # . prologue
14495     55/push-ebp
14496     89/<- %ebp 4/r32/esp
14497     #
14498     (emit-indent *(ebp+8) *Curr-block-depth)
14499     (write-buffered *(ebp+8) "(push-n-zero-bytes ")
14500     (write-int32-hex-buffered *(ebp+8) *(ebp+0xc))
14501     (write-buffered *(ebp+8) ")\n")
14502     (emit-indent *(ebp+8) *Curr-block-depth)
14503     (write-buffered *(ebp+8) "68/push ")
14504     (write-int32-hex-buffered *(ebp+8) *(ebp+0xc))
14505     (write-buffered *(ebp+8) "/imm32\n")
14506 $emit-array-data-initialization:end:
14507     # . epilogue
14508     89/<- %esp 5/r32/ebp
14509     5d/pop-to-ebp
14510     c3/return
14511 
14512 emit-subx-stmt:  # out: (addr buffered-file), stmt: (addr stmt), primitives: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
14513     # . prologue
14514     55/push-ebp
14515     89/<- %ebp 4/r32/esp
14516     # . save registers
14517     50/push-eax
14518     51/push-ecx
14519     # - some special-case primitives that don't actually use the 'primitives' data structure
14520     # var op/ecx: (addr array byte) = lookup(stmt->operation)
14521     8b/-> *(ebp+0xc) 1/r32/ecx
14522     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
14523     89/<- %ecx 0/r32/eax
14524     # array size
14525     {
14526       # if (!string-equal?(stmt->operation, "length")) break
14527       (string-equal? %ecx "length")  # => eax
14528       3d/compare-eax-and 0/imm32
14529       0f 84/jump-if-= break/disp32
14530       (translate-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14531       e9/jump $emit-subx-stmt:end/disp32
14532     }
14533     # index into array
14534     {
14535       # if (!string-equal?(stmt->operation, "index")) break
14536       (string-equal? %ecx "index")  # => eax
14537       3d/compare-eax-and 0/imm32
14538       0f 84/jump-if-= break/disp32
14539       (translate-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14540       e9/jump $emit-subx-stmt:end/disp32
14541     }
14542     # compute-offset for index into array
14543     {
14544       # if (!string-equal?(stmt->operation, "compute-offset")) break
14545       (string-equal? %ecx "compute-offset")  # => eax
14546       3d/compare-eax-and 0/imm32
14547       0f 84/jump-if-= break/disp32
14548       (translate-mu-compute-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14549       e9/jump $emit-subx-stmt:end/disp32
14550     }
14551     # get field from record
14552     {
14553       # if (!string-equal?(stmt->operation, "get")) break
14554       (string-equal? %ecx "get")  # => eax
14555       3d/compare-eax-and 0/imm32
14556       0f 84/jump-if-= break/disp32
14557       (translate-mu-get-stmt *(ebp+8) *(ebp+0xc))
14558       e9/jump $emit-subx-stmt:end/disp32
14559     }
14560     # allocate scalar
14561     {
14562       # if (!string-equal?(stmt->operation, "allocate")) break
14563       (string-equal? %ecx "allocate")  # => eax
14564       3d/compare-eax-and 0/imm32
14565       0f 84/jump-if-= break/disp32
14566       (translate-mu-allocate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14567       e9/jump $emit-subx-stmt:end/disp32
14568     }
14569     # allocate array
14570     {
14571       # if (!string-equal?(stmt->operation, "populate")) break
14572       (string-equal? %ecx "populate")  # => eax
14573       3d/compare-eax-and 0/imm32
14574       0f 84/jump-if-= break/disp32
14575       (translate-mu-populate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14576       e9/jump $emit-subx-stmt:end/disp32
14577     }
14578     # allocate stream
14579     {
14580       # if (!string-equal?(stmt->operation, "populate-stream")) break
14581       (string-equal? %ecx "populate-stream")  # => eax
14582       3d/compare-eax-and 0/imm32
14583       0f 84/jump-if-= break/disp32
14584       (translate-mu-populate-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14585       e9/jump $emit-subx-stmt:end/disp32
14586     }
14587     # read from stream
14588     {
14589       # if (!string-equal?(stmt->operation, "read-from-stream")) break
14590       (string-equal? %ecx "read-from-stream")  # => eax
14591       3d/compare-eax-and 0/imm32
14592       0f 84/jump-if-= break/disp32
14593       (translate-mu-read-from-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14594       e9/jump $emit-subx-stmt:end/disp32
14595     }
14596     # write to stream
14597     {
14598       # if (!string-equal?(stmt->operation, "write-to-stream")) break
14599       (string-equal? %ecx "write-to-stream")  # => eax
14600       3d/compare-eax-and 0/imm32
14601       0f 84/jump-if-= break/disp32
14602       (translate-mu-write-to-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14603       e9/jump $emit-subx-stmt:end/disp32
14604     }
14605     # - if stmt matches a primitive, emit it
14606     {
14607 $emit-subx-stmt:check-for-primitive:
14608       # var curr/eax: (addr primitive)
14609       (find-matching-primitive *(ebp+0x10) *(ebp+0xc))  # primitives, stmt => eax
14610       3d/compare-eax-and 0/imm32
14611       74/jump-if-= break/disp8
14612 $emit-subx-stmt:primitive:
14613       (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax)  # out, stmt, curr
14614       e9/jump $emit-subx-stmt:end/disp32
14615     }
14616     # - otherwise emit a call
14617     # TODO: type-checking
14618 $emit-subx-stmt:call:
14619     (emit-call *(ebp+8) *(ebp+0xc))
14620 $emit-subx-stmt:end:
14621     # . restore registers
14622     59/pop-to-ecx
14623     58/pop-to-eax
14624     # . epilogue
14625     89/<- %esp 5/r32/ebp
14626     5d/pop-to-ebp
14627     c3/return
14628 
14629 translate-mu-length-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
14630     # . prologue
14631     55/push-ebp
14632     89/<- %ebp 4/r32/esp
14633     # . save registers
14634     50/push-eax
14635     51/push-ecx
14636     52/push-edx
14637     53/push-ebx
14638     56/push-esi
14639     # esi = stmt
14640     8b/-> *(ebp+0xc) 6/r32/esi
14641     # var base/ebx: (addr var) = stmt->inouts[0]->value
14642     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
14643     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
14644     89/<- %ebx 0/r32/eax
14645     # var elemsize/ecx: int = array-element-size(base)
14646     (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
14647     89/<- %ecx 0/r32/eax
14648     # var outreg/edx: (addr array byte) = stmt->outputs[0]->value->register
14649     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
14650     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
14651     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
14652     89/<- %edx 0/r32/eax
14653     # if elemsize == 1
14654     {
14655       81 7/subop/compare %ecx 1/imm32
14656       75/jump-if-!= break/disp8
14657 $translate-mu-length-stmt:size-1:
14658       (emit-save-size-to *(ebp+8) %ebx %edx)
14659       e9/jump $translate-mu-length-stmt:end/disp32
14660     }
14661     # if elemsize is a power of 2 less than 256
14662     {
14663       (power-of-2? %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
14664       3d/compare-eax-and 0/imm32/false
14665       74/jump-if-= break/disp8
14666       81 7/subop/compare %ecx 0xff/imm32
14667       7f/jump-if-> break/disp8
14668 $translate-mu-length-stmt:size-power-of-2:
14669       (emit-save-size-to *(ebp+8) %ebx %edx)
14670       (emit-divide-by-shift-right *(ebp+8) %edx %ecx)
14671       e9/jump $translate-mu-length-stmt:end/disp32
14672     }
14673     # otherwise, the complex case
14674     # . emit register spills
14675     {
14676 $translate-mu-length-stmt:complex:
14677       (string-equal? %edx "eax")  # => eax
14678       3d/compare-eax-and 0/imm32/false
14679       75/break-if-!= break/disp8
14680       (emit-indent *(ebp+8) *Curr-block-depth)
14681       (write-buffered *(ebp+8) "50/push-eax\n")
14682     }
14683     {
14684       (string-equal? %edx "ecx")  # => eax
14685       3d/compare-eax-and 0/imm32/false
14686       75/break-if-!= break/disp8
14687       (emit-indent *(ebp+8) *Curr-block-depth)
14688       (write-buffered *(ebp+8) "51/push-ecx\n")
14689     }
14690     {
14691       (string-equal? %edx "edx")  # => eax
14692       3d/compare-eax-and 0/imm32/false
14693       75/break-if-!= break/disp8
14694       (emit-indent *(ebp+8) *Curr-block-depth)
14695       (write-buffered *(ebp+8) "52/push-edx\n")
14696     }
14697     # .
14698     (emit-save-size-to *(ebp+8) %ebx "eax")
14699     (emit-indent *(ebp+8) *Curr-block-depth)
14700     (write-buffered *(ebp+8) "31/xor %edx 2/r32/edx\n")
14701     (emit-indent *(ebp+8) *Curr-block-depth)
14702     (write-buffered *(ebp+8) "b9/copy-to-ecx ")
14703     (write-int32-hex-buffered *(ebp+8) %ecx)
14704     (write-buffered *(ebp+8) "/imm32\n")
14705     (emit-indent *(ebp+8) *Curr-block-depth)
14706     (write-buffered *(ebp+8) "f7 7/subop/idiv-eax-edx-by %ecx\n")
14707     {
14708       (string-equal? %edx "eax")  # => eax
14709       3d/compare-eax-and 0/imm32/false
14710       75/break-if-!= break/disp8
14711       (emit-indent *(ebp+8) *Curr-block-depth)
14712       (write-buffered *(ebp+8) "89/<- %")
14713       (write-buffered *(ebp+8) %edx)
14714       (write-buffered *(ebp+8) " 0/r32/eax\n")
14715     }
14716     # . emit register restores
14717     {
14718       (string-equal? %edx "edx")  # => eax
14719       3d/compare-eax-and 0/imm32/false
14720       75/break-if-!= break/disp8
14721       (emit-indent *(ebp+8) *Curr-block-depth)
14722       (write-buffered *(ebp+8) "5a/pop-to-edx\n")
14723     }
14724     {
14725       (string-equal? %edx "ecx")  # => eax
14726       3d/compare-eax-and 0/imm32/false
14727       75/break-if-!= break/disp8
14728       (emit-indent *(ebp+8) *Curr-block-depth)
14729       (write-buffered *(ebp+8) "59/pop-to-ecx\n")
14730     }
14731     {
14732       (string-equal? %edx "eax")  # => eax
14733       3d/compare-eax-and 0/imm32/false
14734       75/break-if-!= break/disp8
14735       (emit-indent *(ebp+8) *Curr-block-depth)
14736       (write-buffered *(ebp+8) "58/pop-to-eax\n")
14737     }
14738 $translate-mu-length-stmt:end:
14739     # . restore registers
14740     5e/pop-to-esi
14741     5b/pop-to-ebx
14742     5a/pop-to-edx
14743     59/pop-to-ecx
14744     58/pop-to-eax
14745     # . epilogue
14746     89/<- %esp 5/r32/ebp
14747     5d/pop-to-ebp
14748     c3/return
14749 
14750 array-element-size:  # arr: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
14751     # . prologue
14752     55/push-ebp
14753     89/<- %ebp 4/r32/esp
14754     #
14755     (array-element-type-id *(ebp+8) *(ebp+0xc) *(ebp+0x10))  # => eax
14756     (size-of-type-id-as-array-element %eax)  # => eax
14757 $array-element-size:end:
14758     # . epilogue
14759     89/<- %esp 5/r32/ebp
14760     5d/pop-to-ebp
14761     c3/return
14762 
14763 array-element-type-id:  # v: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: type-id
14764     # precondition: n is positive
14765     # . prologue
14766     55/push-ebp
14767     89/<- %ebp 4/r32/esp
14768     #
14769     8b/-> *(ebp+8) 0/r32/eax
14770     # var t/eax: (addr type-tree)
14771     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
14772     # if t == 0 abort
14773     3d/compare-eax-with 0/imm32
14774     0f 84/jump-if-== $array-element-type-id:error0/disp32
14775     # if t->is-atom? abort
14776     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14777     0f 85/jump-if-!= $array-element-type-id:error1/disp32
14778     # if (t->left == addr) t = t->right
14779     {
14780       50/push-eax
14781       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
14782       (is-simple-mu-type? %eax 2)  # addr => eax
14783       3d/compare-eax-with 0/imm32/false
14784       58/pop-to-eax
14785       74/jump-if-= break/disp8
14786 $array-element-type-id:skip-addr:
14787       (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
14788     }
14789     # if t == 0 abort
14790     3d/compare-eax-with 0/imm32
14791     0f 84/jump-if-= $array-element-type-id:error2/disp32
14792     # if t->is-atom? abort
14793     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14794     0f 85/jump-if-!= $array-element-type-id:error2/disp32
14795     # if t->left != array abort
14796     {
14797       50/push-eax
14798       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
14799       (is-simple-mu-type? %eax 3)  # array => eax
14800       3d/compare-eax-with 0/imm32/false
14801       58/pop-to-eax
14802 $array-element-type-id:no-array:
14803       0f 84/jump-if-= $array-element-type-id:error2/disp32
14804     }
14805 $array-element-type-id:skip-array:
14806     # t = t->right
14807     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
14808     # if t == 0 abort
14809     3d/compare-eax-with 0/imm32
14810     0f 84/jump-if-= $array-element-type-id:error2/disp32
14811     # if t->is-atom? abort
14812     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14813     0f 85/jump-if-!= $array-element-type-id:error2/disp32
14814     # return t->left->value
14815     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
14816     8b/-> *(eax+4) 0/r32/eax  # Type-tree-value
14817 $array-element-type-id:end:
14818     # . epilogue
14819     89/<- %esp 5/r32/ebp
14820     5d/pop-to-ebp
14821     c3/return
14822 
14823 $array-element-type-id:error0:
14824     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
14825     50/push-eax
14826     8b/-> *(ebp+8) 0/r32/eax
14827     (lookup *eax *(eax+4))  # Var-name Var-name => eax
14828     (write-buffered *(ebp+0xc) %eax)
14829     58/pop-to-eax
14830     (write-buffered *(ebp+0xc) "' has no type\n")
14831     (flush *(ebp+0xc))
14832     (stop *(ebp+0x10) 1)
14833     # never gets here
14834 
14835 $array-element-type-id:error1:
14836     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
14837     50/push-eax
14838     8b/-> *(ebp+8) 0/r32/eax
14839     (lookup *eax *(eax+4))  # Var-name Var-name => eax
14840     (write-buffered *(ebp+0xc) %eax)
14841     58/pop-to-eax
14842     (write-buffered *(ebp+0xc) "' has atomic type ")
14843     (write-int32-hex-buffered *(ebp+0xc) *(eax+4))  # Type-tree-value
14844     (write-buffered *(ebp+0xc) Newline)
14845     (flush *(ebp+0xc))
14846     (stop *(ebp+0x10) 1)
14847     # never gets here
14848 
14849 $array-element-type-id:error2:
14850     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
14851     50/push-eax
14852     8b/-> *(ebp+8) 0/r32/eax
14853     (lookup *eax *(eax+4))  # Var-name Var-name => eax
14854     (write-buffered *(ebp+0xc) %eax)
14855     58/pop-to-eax
14856     (write-buffered *(ebp+0xc) "' has non-array type\n")
14857     (flush *(ebp+0xc))
14858     (stop *(ebp+0x10) 1)
14859     # never gets here
14860 
14861 size-of-type-id-as-array-element:  # t: type-id -> result/eax: int
14862     # . prologue
14863     55/push-ebp
14864     89/<- %ebp 4/r32/esp
14865     # eax = t
14866     8b/-> *(ebp+8) 0/r32/eax
14867     # if t is 'byte', size is 1
14868     3d/compare-eax-and 8/imm32/byte
14869     {
14870       75/jump-if-!= break/disp8
14871       b8/copy-to-eax 1/imm32
14872       eb/jump $size-of-type-id-as-array-element:end/disp8
14873     }
14874     # otherwise proceed as usual
14875     (size-of-type-id %eax)  # => eax
14876 $size-of-type-id-as-array-element:end:
14877     # . epilogue
14878     89/<- %esp 5/r32/ebp
14879     5d/pop-to-ebp
14880     c3/return
14881 
14882 emit-save-size-to:  # out: (addr buffered-file), base: (addr var), outreg: (addr array byte)
14883     # . prologue
14884     55/push-ebp
14885     89/<- %ebp 4/r32/esp
14886     # . save registers
14887     50/push-eax
14888     53/push-ebx
14889     # ebx = base
14890     8b/-> *(ebp+0xc) 3/r32/ebx
14891     (emit-indent *(ebp+8) *Curr-block-depth)
14892     (write-buffered *(ebp+8) "8b/-> *")
14893     # if base is an (addr array ...) in a register
14894     {
14895       81 7/subop/compare *(ebx+0x18)) 0/imm32  # Var-register
14896       74/jump-if-= break/disp8
14897 $emit-save-size-to:emit-base-from-register:
14898       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
14899       (write-buffered *(ebp+8) %eax)
14900       eb/jump $emit-save-size-to:emit-output/disp8
14901     }
14902     # otherwise if base is an (array ...) on the stack
14903     {
14904       81 7/subop/compare *(ebx+0x14)) 0/imm32  # Var-offset
14905       74/jump-if-= break/disp8
14906 $emit-save-size-to:emit-base-from-stack:
14907       (write-buffered *(ebp+8) "(ebp+")
14908       (write-int32-hex-buffered *(ebp+8) *(ebx+0x14))  # Var-offset
14909       (write-buffered *(ebp+8) ")")
14910     }
14911 $emit-save-size-to:emit-output:
14912     (write-buffered *(ebp+8) " ")
14913     (get Mu-registers *(ebp+0x10) 0xc "Mu-registers")  # => eax
14914     (write-int32-hex-buffered *(ebp+8) *eax)
14915     (write-buffered *(ebp+8) "/r32\n")
14916 $emit-save-size-to:end:
14917     # . restore registers
14918     5b/pop-to-ebx
14919     58/pop-to-eax
14920     # . epilogue
14921     89/<- %esp 5/r32/ebp
14922     5d/pop-to-ebp
14923     c3/return
14924 
14925 emit-divide-by-shift-right:  # out: (addr buffered-file), reg: (addr array byte), size: int
14926     # . prologue
14927     55/push-ebp
14928     89/<- %ebp 4/r32/esp
14929     # . save registers
14930     50/push-eax
14931     #
14932     (emit-indent *(ebp+8) *Curr-block-depth)
14933     (write-buffered *(ebp+8) "c1/shift 5/subop/>> %")
14934     (write-buffered *(ebp+8) *(ebp+0xc))
14935     (write-buffered *(ebp+8) Space)
14936     (num-shift-rights *(ebp+0x10))  # => eax
14937     (write-int32-hex-buffered *(ebp+8) %eax)
14938     (write-buffered *(ebp+8) "/imm8\n")
14939 $emit-divide-by-shift-right:end:
14940     # . restore registers
14941     58/pop-to-eax
14942     # . epilogue
14943     89/<- %esp 5/r32/ebp
14944     5d/pop-to-ebp
14945     c3/return
14946 
14947 translate-mu-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
14948     # . prologue
14949     55/push-ebp
14950     89/<- %ebp 4/r32/esp
14951     # . save registers
14952     51/push-ecx
14953     # ecx = stmt
14954     8b/-> *(ebp+0xc) 1/r32/ecx
14955     # var base/ecx: (addr var) = stmt->inouts[0]
14956     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
14957     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
14958     89/<- %ecx 0/r32/eax
14959     # if (var->register) do one thing
14960     {
14961       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
14962       74/jump-if-= break/disp8
14963       # TODO: ensure there's no dereference
14964       (translate-mu-index-stmt-with-array-in-register *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
14965       eb/jump $translate-mu-index-stmt:end/disp8
14966     }
14967     # if (var->offset) do a different thing
14968     {
14969       81 7/subop/compare *(ecx+0x14) 0/imm32  # Var-offset
14970       74/jump-if-= break/disp8
14971       # TODO: ensure there's no dereference
14972       (translate-mu-index-stmt-with-array-on-stack *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
14973       eb/jump $translate-mu-index-stmt:end/disp8
14974     }
14975 $translate-mu-index-stmt:end:
14976     # . restore registers
14977     59/pop-to-ecx
14978     # . epilogue
14979     89/<- %esp 5/r32/ebp
14980     5d/pop-to-ebp
14981     c3/return
14982 
14983 $translate-mu-index-stmt-with-array:error1:
14984     (write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input must either lie in a register or be a literal\n")
14985     (flush *(ebp+0x10))
14986     (stop *(ebp+0x14) 1)
14987     # never gets here
14988 
14989 $translate-mu-index-stmt-with-array:error2:
14990     (write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input when in a register must be an int or offset\n")
14991     (flush *(ebp+0x10))
14992     (stop *(ebp+0x14) 1)
14993     # never gets here
14994 
14995 translate-mu-index-stmt-with-array-in-register:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
14996     # . prologue
14997     55/push-ebp
14998     89/<- %ebp 4/r32/esp
14999     # . save registers
15000     50/push-eax
15001     51/push-ecx
15002     52/push-edx
15003     53/push-ebx
15004     #
15005     (emit-indent *(ebp+8) *Curr-block-depth)
15006     (write-buffered *(ebp+8) "8d/copy-address *(")
15007     # TODO: ensure inouts[0] is in a register and not dereferenced
15008 $translate-mu-index-stmt-with-array-in-register:emit-base:
15009     # ecx = stmt
15010     8b/-> *(ebp+0xc) 1/r32/ecx
15011     # var base/ebx: (addr var) = inouts[0]
15012     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15013     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15014     89/<- %ebx 0/r32/eax
15015     # print base->register " + "
15016     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
15017     (write-buffered *(ebp+8) %eax)
15018     (write-buffered *(ebp+8) " + ")
15019     # var index/edx: (addr var) = inouts[1]
15020     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15021     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
15022     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15023     89/<- %edx 0/r32/eax
15024     # if index->register
15025     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
15026     {
15027       0f 84/jump-if-= break/disp32
15028 $translate-mu-index-stmt-with-array-in-register:emit-register-index:
15029       # if index is an int
15030       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
15031       (is-simple-mu-type? %eax 1)  # int => eax
15032       3d/compare-eax-and 0/imm32/false
15033       {
15034         0f 84/jump-if-= break/disp32
15035 $translate-mu-index-stmt-with-array-in-register:emit-int-register-index:
15036         # print index->register "<<" log2(array-element-size(base)) " + 4) "
15037         # . index->register "<<"
15038         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
15039         (write-buffered *(ebp+8) %eax)
15040         (write-buffered *(ebp+8) "<<")
15041         # . log2(array-element-size(base->type))
15042         # TODO: ensure size is a power of 2
15043         (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
15044         (num-shift-rights %eax)  # => eax
15045         (write-int32-hex-buffered *(ebp+8) %eax)
15046         e9/jump $translate-mu-index-stmt-with-array-in-register:emit-register-index-done/disp32
15047       }
15048       # if index->type is any other atom, abort
15049       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
15050       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
15051       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
15052       # if index has type (offset ...)
15053       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
15054       (is-simple-mu-type? %eax 7)  # => eax
15055       3d/compare-eax-and 0/imm32/false
15056       {
15057         0f 84/jump-if-= break/disp32
15058         # print index->register
15059 $translate-mu-index-stmt-with-array-in-register:emit-offset-register-index:
15060         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
15061         (write-buffered *(ebp+8) %eax)
15062       }
15063 $translate-mu-index-stmt-with-array-in-register:emit-register-index-done:
15064       (write-buffered *(ebp+8) " + 4) ")
15065       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
15066     }
15067     # otherwise if index is a literal
15068     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
15069     (is-simple-mu-type? %eax 0)  # => eax
15070     3d/compare-eax-and 0/imm32/false
15071     {
15072       0f 84/jump-if-= break/disp32
15073 $translate-mu-index-stmt-with-array-in-register:emit-literal-index:
15074       # var index-value/edx: int = parse-hex-int(index->name)
15075       (lookup *edx *(edx+4))  # Var-name Var-name => eax
15076       (parse-hex-int %eax)  # => eax
15077       89/<- %edx 0/r32/eax
15078       # offset = idx-value * array-element-size(base->type)
15079       (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
15080       f7 4/subop/multiply-into-eax %edx  # clobbers edx
15081       # offset += 4 for array size
15082       05/add-to-eax 4/imm32
15083       # TODO: check edx for overflow
15084       # print offset
15085       (write-int32-hex-buffered *(ebp+8) %eax)
15086       (write-buffered *(ebp+8) ") ")
15087       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
15088     }
15089     # otherwise abort
15090     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
15091 $translate-mu-index-stmt-with-array-in-register:emit-output:
15092     # outputs[0] "/r32"
15093     8b/-> *(ebp+0xc) 1/r32/ecx
15094     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
15095     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15096     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15097     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
15098     (write-int32-hex-buffered *(ebp+8) *eax)
15099     (write-buffered *(ebp+8) "/r32\n")
15100 $translate-mu-index-stmt-with-array-in-register:end:
15101     # . restore registers
15102     5b/pop-to-ebx
15103     5a/pop-to-edx
15104     59/pop-to-ecx
15105     58/pop-to-eax
15106     # . epilogue
15107     89/<- %esp 5/r32/ebp
15108     5d/pop-to-ebp
15109     c3/return
15110 
15111 translate-mu-index-stmt-with-array-on-stack:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15112     # . prologue
15113     55/push-ebp
15114     89/<- %ebp 4/r32/esp
15115     # . save registers
15116     50/push-eax
15117     51/push-ecx
15118     52/push-edx
15119     53/push-ebx
15120     #
15121     (emit-indent *(ebp+8) *Curr-block-depth)
15122     (write-buffered *(ebp+8) "8d/copy-address *(ebp + ")
15123     # var curr/edx: (addr stmt-var) = lookup(stmt->inouts)
15124     8b/-> *(ebp+0xc) 0/r32/eax
15125     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15126     89/<- %edx 0/r32/eax
15127     # var base/ecx: (addr var) = lookup(curr->value)
15128     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15129     89/<- %ecx 0/r32/eax
15130     # var curr2/eax: (addr stmt-var) = lookup(curr->next)
15131     (lookup *(edx+8) *(edx+0xc))  # Stmt-var-next Stmt-var-next => eax
15132     # var index/edx: (handle var) = curr2->value
15133     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15134     89/<- %edx 0/r32/eax
15135     # if index->register
15136     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
15137     {
15138       0f 84/jump-if-= break/disp32
15139 $translate-mu-index-stmt-with-array-on-stack:emit-register-index:
15140       # if index is an int
15141       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
15142       (is-simple-mu-type? %eax 1)  # int => eax
15143       3d/compare-eax-and 0/imm32/false
15144       {
15145         0f 84/jump-if-= break/disp32
15146 $translate-mu-index-stmt-with-array-on-stack:emit-int-register-index:
15147         # print index->register "<<" log2(array-element-size(base)) " + " base->offset+4
15148         # . inouts[1]->register "<<"
15149         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
15150         (write-buffered *(ebp+8) %eax)
15151         (write-buffered *(ebp+8) "<<")
15152         # . log2(array-element-size(base))
15153         # TODO: ensure size is a power of 2
15154         (array-element-size %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
15155         (num-shift-rights %eax)  # => eax
15156         (write-int32-hex-buffered *(ebp+8) %eax)
15157         #
15158         (write-buffered *(ebp+8) " + ")
15159         #
15160         8b/-> *(ecx+0x14) 0/r32/eax  # Var-offset
15161         05/add-to-eax 4/imm32  # for array length
15162         (write-int32-hex-buffered *(ebp+8) %eax)
15163         e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done/disp32
15164       }
15165       # if index->type is any other atom, abort
15166       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
15167       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
15168       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
15169       # if index has type (offset ...)
15170       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
15171       (is-simple-mu-type? %eax 7)  # => eax
15172       3d/compare-eax-and 0/imm32/false
15173       {
15174         0f 84/jump-if-= break/disp32
15175         # print index->register
15176 $translate-mu-index-stmt-with-array-on-stack:emit-offset-register-index:
15177         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
15178         (write-buffered *(ebp+8) %eax)
15179       }
15180 $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done:
15181       (write-buffered *(ebp+8) ") ")
15182       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
15183     }
15184     # otherwise if index is a literal
15185     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
15186     (is-simple-mu-type? %eax 0)  # => eax
15187     3d/compare-eax-and 0/imm32/false
15188     {
15189       0f 84/jump-if-= break/disp32
15190 $translate-mu-index-stmt-with-array-on-stack:emit-literal-index:
15191       # var idx-value/edx: int = parse-hex-int(index->name)
15192       (lookup *edx *(edx+4))  # Var-name Var-name => eax
15193       (parse-hex-int %eax)  # Var-name => eax
15194       89/<- %edx 0/r32/eax
15195       # offset = idx-value * array-element-size(base)
15196       (array-element-size %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
15197       f7 4/subop/multiply-into-eax %edx  # clobbers edx
15198       # offset += base->offset
15199       03/add *(ecx+0x14) 0/r32/eax  # Var-offset
15200       # offset += 4 for array size
15201       05/add-to-eax 4/imm32
15202       # TODO: check edx for overflow
15203       # print offset
15204       (write-int32-hex-buffered *(ebp+8) %eax)
15205       (write-buffered *(ebp+8) ") ")
15206       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
15207     }
15208     # otherwise abort
15209     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
15210 $translate-mu-index-stmt-with-array-on-stack:emit-output:
15211     # outputs[0] "/r32"
15212     8b/-> *(ebp+0xc) 0/r32/eax
15213     (lookup *(eax+0x14) *(eax+0x18))  # Stmt1-outputs Stmt1-outputs => eax
15214     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15215     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15216     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
15217     (write-int32-hex-buffered *(ebp+8) *eax)
15218     (write-buffered *(ebp+8) "/r32\n")
15219 $translate-mu-index-stmt-with-array-on-stack:end:
15220     # . restore registers
15221     5b/pop-to-ebx
15222     5a/pop-to-edx
15223     59/pop-to-ecx
15224     58/pop-to-eax
15225     # . epilogue
15226     89/<- %esp 5/r32/ebp
15227     5d/pop-to-ebp
15228     c3/return
15229 
15230 translate-mu-compute-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15231     # . prologue
15232     55/push-ebp
15233     89/<- %ebp 4/r32/esp
15234     # . save registers
15235     50/push-eax
15236     51/push-ecx
15237     52/push-edx
15238     53/push-ebx
15239     #
15240     (emit-indent *(ebp+8) *Curr-block-depth)
15241     (write-buffered *(ebp+8) "69/multiply")
15242     # ecx = stmt
15243     8b/-> *(ebp+0xc) 1/r32/ecx
15244     # var first-inout/ebx: (addr stmt-var) = stmt->inouts[0]
15245     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15246     89/<- %ebx 0/r32/eax
15247 $translate-mu-compute-index-stmt:emit-index:
15248     (lookup *(ebx+8) *(ebx+0xc))  # Stmt-var-next Stmt-var-next => eax
15249     (emit-subx-var-as-rm32 *(ebp+8) %eax)
15250     (write-buffered *(ebp+8) Space)
15251 $translate-mu-compute-index-stmt:emit-elem-size:
15252     # var base/ebx: (addr var)
15253     (lookup *ebx *(ebx+4))  # Stmt-var-value Stmt-var-value => eax
15254     89/<- %ebx 0/r32/eax
15255     # print array-element-size(base)
15256     (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
15257     (write-int32-hex-buffered *(ebp+8) %eax)
15258     (write-buffered *(ebp+8) "/imm32 ")
15259 $translate-mu-compute-index-stmt:emit-output:
15260     # outputs[0] "/r32"
15261     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
15262     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15263     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15264     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
15265     (write-int32-hex-buffered *(ebp+8) *eax)
15266     (write-buffered *(ebp+8) "/r32\n")
15267 $translate-mu-compute-index-stmt:end:
15268     # . restore registers
15269     5b/pop-to-ebx
15270     5a/pop-to-edx
15271     59/pop-to-ecx
15272     58/pop-to-eax
15273     # . epilogue
15274     89/<- %esp 5/r32/ebp
15275     5d/pop-to-ebp
15276     c3/return
15277 
15278 translate-mu-get-stmt:  # out: (addr buffered-file), stmt: (addr stmt)
15279     # . prologue
15280     55/push-ebp
15281     89/<- %ebp 4/r32/esp
15282     # . save registers
15283     50/push-eax
15284     51/push-ecx
15285     52/push-edx
15286     #
15287     (emit-indent *(ebp+8) *Curr-block-depth)
15288     (write-buffered *(ebp+8) "8d/copy-address ")
15289     # ecx = stmt
15290     8b/-> *(ebp+0xc) 1/r32/ecx
15291     # var offset/edx: int = get offset of stmt
15292     (mu-get-offset %ecx)  # => eax
15293     89/<- %edx 0/r32/eax
15294     # var base/eax: (addr var) = stmt->inouts->value
15295     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15296     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15297     # if base is in a register
15298     81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
15299     {
15300       0f 84/jump-if-= break/disp32
15301 $translate-mu-get-stmt:emit-register-input:
15302       # emit "*(" base->register " + " offset ") "
15303       (write-buffered *(ebp+8) "*(")
15304       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15305       (write-buffered *(ebp+8) %eax)
15306       (write-buffered *(ebp+8) " + ")
15307       (write-int32-hex-buffered *(ebp+8) %edx)
15308       (write-buffered *(ebp+8) ") ")
15309       e9/jump $translate-mu-get-stmt:emit-output/disp32
15310     }
15311     # otherwise base is on the stack
15312     {
15313 $translate-mu-get-stmt:emit-stack-input:
15314       # emit "*(ebp + " inouts[0]->stack-offset + offset ") "
15315       (write-buffered *(ebp+8) "*(ebp+")
15316       03/add *(eax+0x14) 2/r32/edx  # Var-offset
15317       (write-int32-hex-buffered *(ebp+8) %edx)
15318       (write-buffered *(ebp+8) ") ")
15319       eb/jump $translate-mu-get-stmt:emit-output/disp8
15320     }
15321 $translate-mu-get-stmt:emit-output:
15322     # var output/eax: (addr var) = stmt->outputs->value
15323     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
15324     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15325     # emit offset->register "/r32"
15326     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15327     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
15328     (write-int32-hex-buffered *(ebp+8) *eax)
15329     (write-buffered *(ebp+8) "/r32\n")
15330 $translate-mu-get-stmt:end:
15331     # . restore registers
15332     5a/pop-to-edx
15333     59/pop-to-ecx
15334     58/pop-to-eax
15335     # . epilogue
15336     89/<- %esp 5/r32/ebp
15337     5d/pop-to-ebp
15338     c3/return
15339 
15340 translate-mu-allocate-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15341     # . prologue
15342     55/push-ebp
15343     89/<- %ebp 4/r32/esp
15344     # . save registers
15345     50/push-eax
15346     56/push-esi
15347     57/push-edi
15348     # esi = stmt
15349     8b/-> *(ebp+0xc) 6/r32/esi
15350     # var target/edi: (addr stmt-var) = stmt->inouts[0]
15351     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15352     89/<- %edi 0/r32/eax
15353     #
15354     (emit-indent *(ebp+8) *Curr-block-depth)
15355     (write-buffered *(ebp+8) "(allocate Heap ")
15356     (addr-handle-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
15357     (write-int32-hex-buffered *(ebp+8) %eax)
15358     (emit-subx-call-operand *(ebp+8) %edi)
15359     (write-buffered *(ebp+8) ")\n")
15360 $translate-mu-allocate-stmt:end:
15361     # . restore registers
15362     5f/pop-to-edi
15363     5e/pop-to-esi
15364     58/pop-to-eax
15365     # . epilogue
15366     89/<- %esp 5/r32/ebp
15367     5d/pop-to-ebp
15368     c3/return
15369 
15370 addr-handle-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
15371     # . prologue
15372     55/push-ebp
15373     89/<- %ebp 4/r32/esp
15374     # var t/eax: (addr type-tree) = s->value->type
15375     8b/-> *(ebp+8) 0/r32/eax
15376     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15377     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
15378     # TODO: check eax != 0
15379     # TODO: check !t->is-atom?
15380     # TODO: check t->left == addr
15381     # t = t->right
15382 $addr-handle-payload-size:skip-addr:
15383     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15384     # TODO: check eax != 0
15385     # TODO: check !t->is-atom?
15386     # TODO: check t->left == handle
15387     # t = t->right
15388 $addr-handle-payload-size:skip-handle:
15389     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15390     # TODO: check eax != 0
15391     # if !t->is-atom? t = t->left
15392     81 7/subop/compare *eax 0/imm32/false
15393     {
15394       75/jump-if-!= break/disp8
15395       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
15396     }
15397     # TODO: check t->is-atom?
15398     # return size(t->value)
15399     (size-of-type-id *(eax+4))  # Type-tree-value => eax
15400 $addr-handle-payload-size:end:
15401     # . epilogue
15402     89/<- %esp 5/r32/ebp
15403     5d/pop-to-ebp
15404     c3/return
15405 
15406 addr-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
15407     # . prologue
15408     55/push-ebp
15409     89/<- %ebp 4/r32/esp
15410     # var t/eax: (addr type-tree) = s->value->type
15411     8b/-> *(ebp+8) 0/r32/eax
15412     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15413     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
15414     # TODO: check eax != 0
15415     # TODO: check !t->is-atom?
15416     # TODO: check t->left == addr
15417     # t = t->right
15418 $addr-payload-size:skip-addr:
15419     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15420     # TODO: check eax != 0
15421     # if !t->is-atom? t = t->left
15422     81 7/subop/compare *eax 0/imm32/false
15423     {
15424       75/jump-if-!= break/disp8
15425       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
15426     }
15427     # TODO: check t->is-atom?
15428     # return size(t->value)
15429     (size-of-type-id *(eax+4))  # Type-tree-value => eax
15430 $addr-payload-size:end:
15431     # . epilogue
15432     89/<- %esp 5/r32/ebp
15433     5d/pop-to-ebp
15434     c3/return
15435 
15436 translate-mu-populate-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15437     # . prologue
15438     55/push-ebp
15439     89/<- %ebp 4/r32/esp
15440     # . save registers
15441     50/push-eax
15442     51/push-ecx
15443     56/push-esi
15444     57/push-edi
15445     # esi = stmt
15446     8b/-> *(ebp+0xc) 6/r32/esi
15447     # var target/edi: (addr stmt-var) = stmt->inouts[0]
15448     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15449     89/<- %edi 0/r32/eax
15450     # var len/ecx: (addr stmt-var) = stmt->inouts[1]
15451     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
15452     89/<- %ecx 0/r32/eax
15453     #
15454     (emit-indent *(ebp+8) *Curr-block-depth)
15455     (write-buffered *(ebp+8) "(allocate-array2 Heap ")
15456     (addr-handle-array-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
15457     (write-int32-hex-buffered *(ebp+8) %eax)
15458     (emit-subx-call-operand *(ebp+8) %ecx)
15459     (emit-subx-call-operand *(ebp+8) %edi)
15460     (write-buffered *(ebp+8) ")\n")
15461 $translate-mu-populate-stmt:end:
15462     # . restore registers
15463     5f/pop-to-edi
15464     5e/pop-to-esi
15465     59/pop-to-ecx
15466     58/pop-to-eax
15467     # . epilogue
15468     89/<- %esp 5/r32/ebp
15469     5d/pop-to-ebp
15470     c3/return
15471 
15472 translate-mu-populate-stream-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15473     # . prologue
15474     55/push-ebp
15475     89/<- %ebp 4/r32/esp
15476     # . save registers
15477     50/push-eax
15478     51/push-ecx
15479     56/push-esi
15480     57/push-edi
15481     # esi = stmt
15482     8b/-> *(ebp+0xc) 6/r32/esi
15483     # var target/edi: (addr stmt-var) = stmt->inouts[0]
15484     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15485     89/<- %edi 0/r32/eax
15486     # var len/ecx: (addr stmt-var) = stmt->inouts[1]
15487     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
15488     89/<- %ecx 0/r32/eax
15489     #
15490     (emit-indent *(ebp+8) *Curr-block-depth)
15491     (write-buffered *(ebp+8) "(new-stream Heap ")
15492     (addr-handle-array-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
15493     (write-int32-hex-buffered *(ebp+8) %eax)
15494     (emit-subx-call-operand *(ebp+8) %ecx)
15495     (emit-subx-call-operand *(ebp+8) %edi)
15496     (write-buffered *(ebp+8) ")\n")
15497 $translate-mu-populate-stream-stmt:end:
15498     # . restore registers
15499     5f/pop-to-edi
15500     5e/pop-to-esi
15501     59/pop-to-ecx
15502     58/pop-to-eax
15503     # . epilogue
15504     89/<- %esp 5/r32/ebp
15505     5d/pop-to-ebp
15506     c3/return
15507 
15508 translate-mu-read-from-stream-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15509     # . prologue
15510     55/push-ebp
15511     89/<- %ebp 4/r32/esp
15512     # . save registers
15513     50/push-eax
15514     51/push-ecx
15515     56/push-esi
15516     57/push-edi
15517     # esi = stmt
15518     8b/-> *(ebp+0xc) 6/r32/esi
15519     # var stream/ecx: (addr stmt-var) = stmt->inouts[0]
15520     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15521     89/<- %ecx 0/r32/eax
15522     # var target/edi: (addr stmt-var) = stmt->inouts[1]
15523     (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
15524     89/<- %edi 0/r32/eax
15525     #
15526     (emit-indent *(ebp+8) *Curr-block-depth)
15527     (write-buffered *(ebp+8) "(read-from-stream")
15528     (emit-subx-call-operand *(ebp+8) %ecx)
15529     (emit-subx-call-operand *(ebp+8) %edi)
15530     (write-buffered *(ebp+8) Space)
15531     (addr-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
15532     (write-int32-hex-buffered *(ebp+8) %eax)
15533     (write-buffered *(ebp+8) ")\n")
15534 $translate-mu-read-from-stream-stmt:end:
15535     # . restore registers
15536     5f/pop-to-edi
15537     5e/pop-to-esi
15538     59/pop-to-ecx
15539     58/pop-to-eax
15540     # . epilogue
15541     89/<- %esp 5/r32/ebp
15542     5d/pop-to-ebp
15543     c3/return
15544 
15545 translate-mu-write-to-stream-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15546     # . prologue
15547     55/push-ebp
15548     89/<- %ebp 4/r32/esp
15549     # . save registers
15550     50/push-eax
15551     51/push-ecx
15552     56/push-esi
15553     57/push-edi
15554     # esi = stmt
15555     8b/-> *(ebp+0xc) 6/r32/esi
15556     # var stream/ecx: (addr stmt-var) = stmt->inouts[0]
15557     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15558     89/<- %ecx 0/r32/eax
15559     # var target/edi: (addr stmt-var) = stmt->inouts[1]
15560     (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
15561     89/<- %edi 0/r32/eax
15562     #
15563     (emit-indent *(ebp+8) *Curr-block-depth)
15564     (write-buffered *(ebp+8) "(write-to-stream")
15565     (emit-subx-call-operand *(ebp+8) %ecx)
15566     (flush *(ebp+8))
15567     (emit-subx-call-operand *(ebp+8) %edi)
15568     (flush *(ebp+8))
15569     (write-buffered *(ebp+8) Space)
15570     (flush *(ebp+8))
15571     (addr-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
15572     (write-int32-hex-buffered *(ebp+8) %eax)
15573     (write-buffered *(ebp+8) ")\n")
15574 $translate-mu-write-to-stream-stmt:end:
15575     # . restore registers
15576     5f/pop-to-edi
15577     5e/pop-to-esi
15578     59/pop-to-ecx
15579     58/pop-to-eax
15580     # . epilogue
15581     89/<- %esp 5/r32/ebp
15582     5d/pop-to-ebp
15583     c3/return
15584 
15585 addr-handle-array-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
15586     # . prologue
15587     55/push-ebp
15588     89/<- %ebp 4/r32/esp
15589     # var t/eax: (addr type-tree) = s->value->type
15590     8b/-> *(ebp+8) 0/r32/eax
15591     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15592     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
15593     # TODO: check eax != 0
15594     # TODO: check !t->is-atom?
15595     # TODO: check t->left == addr
15596     # t = t->right
15597 $addr-handle-array-payload-size:skip-addr:
15598     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15599     # TODO: check eax != 0
15600     # TODO: check !t->is-atom?
15601     # TODO: check t->left == handle
15602     # t = t->right
15603 $addr-handle-array-payload-size:skip-handle:
15604     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15605     # TODO: check eax != 0
15606     # TODO: check !t->is-atom?
15607     # TODO: check t->left == array
15608     # t = t->right
15609 $addr-handle-array-payload-size:skip-array:
15610     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15611     # TODO: check eax != 0
15612     # if !t->is-atom? t = t->left
15613     81 7/subop/compare *eax 0/imm32/false
15614     {
15615       75/jump-if-!= break/disp8
15616       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
15617     }
15618 $addr-handle-array-payload-size:compute-size:
15619     # TODO: check t->is-atom?
15620     # return size(t->value)
15621     (size-of-type-id-as-array-element *(eax+4))  # Type-tree-value => eax
15622 $addr-handle-array-payload-size:end:
15623     # . epilogue
15624     89/<- %esp 5/r32/ebp
15625     5d/pop-to-ebp
15626     c3/return
15627 
15628 power-of-2?:  # n: int, err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: boolean
15629     # precondition: n is positive
15630     # . prologue
15631     55/push-ebp
15632     89/<- %ebp 4/r32/esp
15633     # eax = n
15634     8b/-> *(ebp+8) 0/r32/eax
15635     # if (n < 0) abort
15636     3d/compare-eax-with 0/imm32
15637     0f 8c/jump-if-< $power-of-2?:abort/disp32
15638     # var tmp/eax: int = n-1
15639     48/decrement-eax
15640     # var tmp2/eax: int = n & tmp
15641     23/and-> *(ebp+8) 0/r32/eax
15642     # return (tmp2 == 0)
15643     3d/compare-eax-and 0/imm32
15644     0f 94/set-byte-if-= %al
15645     81 4/subop/and %eax 0xff/imm32
15646 $power-of-2?:end:
15647     # . epilogue
15648     89/<- %esp 5/r32/ebp
15649     5d/pop-to-ebp
15650     c3/return
15651 
15652 $power-of-2?:abort:
15653     (write-buffered *(ebp+0xc) "power-of-2?: negative number\n")
15654     (flush *(ebp+0xc))
15655     (stop *(ebp+0x10) 1)
15656     # never gets here
15657 
15658 num-shift-rights:  # n: int -> result/eax: int
15659     # precondition: n is a positive power of 2
15660     # . prologue
15661     55/push-ebp
15662     89/<- %ebp 4/r32/esp
15663     # . save registers
15664     51/push-ecx
15665     # var curr/ecx: int = n
15666     8b/-> *(ebp+8) 1/r32/ecx
15667     # result = 0
15668     b8/copy-to-eax 0/imm32
15669     {
15670       # if (curr <= 1) break
15671       81 7/subop/compare %ecx 1/imm32
15672       7e/jump-if-<= break/disp8
15673       40/increment-eax
15674       c1/shift 5/subop/arithmetic-right %ecx 1/imm8
15675       eb/jump loop/disp8
15676     }
15677 $num-shift-rights:end:
15678     # . restore registers
15679     59/pop-to-ecx
15680     # . epilogue
15681     89/<- %esp 5/r32/ebp
15682     5d/pop-to-ebp
15683     c3/return
15684 
15685 mu-get-offset:  # stmt: (addr stmt) -> result/eax: int
15686     # . prologue
15687     55/push-ebp
15688     89/<- %ebp 4/r32/esp
15689     # var second-inout/eax: (addr stmt-var) = stmt->inouts->next
15690     8b/-> *(ebp+8) 0/r32/eax
15691     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15692     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
15693     # var output-var/eax: (addr var) = second-inout->value
15694     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15695 #?     (write-buffered Stderr "mu-get-offset: ")
15696 #?     (write-int32-hex-buffered Stderr %eax)
15697 #?     (write-buffered Stderr " name: ")
15698 #?     50/push-eax
15699 #?     (lookup *eax *(eax+4))  # Var-name
15700 #?     (write-buffered Stderr %eax)
15701 #?     58/pop-to-eax
15702 #?     (write-buffered Stderr Newline)
15703 #?     (flush Stderr)
15704     # return output-var->stack-offset
15705     8b/-> *(eax+0x14) 0/r32/eax  # Var-offset
15706 #?     (write-buffered Stderr "=> ")
15707 #?     (write-int32-hex-buffered Stderr %eax)
15708 #?     (write-buffered Stderr Newline)
15709 #?     (flush Stderr)
15710 $emit-get-offset:end:
15711     # . epilogue
15712     89/<- %esp 5/r32/ebp
15713     5d/pop-to-ebp
15714     c3/return
15715 
15716 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)
15717     # . prologue
15718     55/push-ebp
15719     89/<- %ebp 4/r32/esp
15720     # . save registers
15721     50/push-eax
15722     51/push-ecx
15723     56/push-esi
15724     # esi = block
15725     8b/-> *(ebp+0xc) 6/r32/esi
15726     # block->var->block-depth = *Curr-block-depth
15727     (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
15728     8b/-> *Curr-block-depth 1/r32/ecx
15729     89/<- *(eax+0x10) 1/r32/ecx  # Var-block-depth
15730     # var stmts/eax: (addr list stmt) = lookup(block->statements)
15731     (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
15732     #
15733     {
15734 $emit-subx-block:check-empty:
15735       3d/compare-eax-and 0/imm32
15736       0f 84/jump-if-= break/disp32
15737       (emit-indent *(ebp+8) *Curr-block-depth)
15738       (write-buffered *(ebp+8) "{\n")
15739       # var v/ecx: (addr var) = lookup(block->var)
15740       (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
15741       89/<- %ecx 0/r32/eax
15742       #
15743       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
15744       (write-buffered *(ebp+8) %eax)
15745       (write-buffered *(ebp+8) ":loop:\n")
15746       ff 0/subop/increment *Curr-block-depth
15747       (push *(ebp+0x10) *(esi+0xc))  # Block-var
15748       (push *(ebp+0x10) *(esi+0x10))  # Block-var
15749       (push *(ebp+0x10) 0)  # false
15750       # emit block->statements
15751       (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
15752       (emit-subx-stmt-list *(ebp+8) %eax *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
15753       (pop *(ebp+0x10))  # => eax
15754       (pop *(ebp+0x10))  # => eax
15755       (pop *(ebp+0x10))  # => eax
15756       ff 1/subop/decrement *Curr-block-depth
15757       (emit-indent *(ebp+8) *Curr-block-depth)
15758       (write-buffered *(ebp+8) "}\n")
15759       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
15760       (write-buffered *(ebp+8) %eax)
15761       (write-buffered *(ebp+8) ":break:\n")
15762     }
15763 $emit-subx-block:end:
15764     # . restore registers
15765     5e/pop-to-esi
15766     59/pop-to-ecx
15767     58/pop-to-eax
15768     # . epilogue
15769     89/<- %esp 5/r32/ebp
15770     5d/pop-to-ebp
15771     c3/return
15772 
15773 # Primitives supported
15774 # See mu_instructions for a summary of this linked-list data structure.
15775 #
15776 # For each operation, put variants with hard-coded registers before flexible ones.
15777 #
15778 # Unfortunately, our restrictions on addresses require that various fields in
15779 # primitives be handles, which complicates these definitions.
15780 #   - we need to insert dummy fields all over the place for fake alloc-ids
15781 #   - we can't use our syntax sugar of quoted literals for string fields
15782 #
15783 # Fake alloc-ids are needed because our type definitions up top require
15784 # handles but it's clearer to statically allocate these long-lived objects.
15785 # Fake alloc-ids are perfectly safe, but they can't be reclaimed.
15786 #
15787 # Every 'object' below starts with a fake alloc-id. It may also contain other
15788 # fake alloc-ids for various handle fields.
15789 #
15790 # I think of objects starting with a fake alloc-id as having type 'payload'.
15791 # It's not really intended to be created dynamically; for that use `allocate`
15792 # as usual.
15793 #
15794 # Idea for a notation to simplify such definitions:
15795 #   _Primitive-increment-eax:  # (payload primitive)
15796 #     0x11/alloc-id:fake:payload
15797 #     0x11 @(0x11 "increment")  # name
15798 #     0 0                       # inouts
15799 #     0x11 @(0x11/payload
15800 #            0x11 @(0x11/payload  # List-value
15801 #                   0 0             # Var-name
15802 #                   0x11 @(0x11     # Var-type
15803 #                          1/is-atom
15804 #                          1/value 0/unused   # Type-tree-left
15805 #                          0 0                # Type-tree-right
15806 #                         )
15807 #                   1               # block-depth
15808 #                   0               # stack-offset
15809 #                   0x11 @(0x11 "eax")  # Var-register
15810 #                  )
15811 #            0 0)                 # List-next
15812 #     ...
15813 #     _Primitive-increment-ecx/imm32/next
15814 #   ...
15815 # Awfully complex and non-obvious. But also clearly signals there's something
15816 # to learn here, so may be worth trying.
15817 #
15818 # '@' is just an initial thought. Punctuation used so far in Mu: () * % # / "
15819 #
15820 # For now we'll continue to just use comments and manually ensure they stay up
15821 # to date.
15822 == data
15823 Primitives:  # (addr primitive)
15824 # - increment/decrement
15825 _Primitive-increment-eax:  # (addr primitive)
15826     # var/eax <- increment => 40/increment-eax
15827     0x11/imm32/alloc-id:fake
15828     _string-increment/imm32/name
15829     0/imm32/no-inouts
15830     0/imm32/no-inouts
15831     0x11/imm32/alloc-id:fake
15832     Single-int-var-in-eax/imm32/outputs
15833     0x11/imm32/alloc-id:fake
15834     _string_40_increment_eax/imm32/subx-name
15835     0/imm32/no-rm32
15836     0/imm32/no-r32
15837     0/imm32/no-imm32
15838     0/imm32/no-imm8
15839     0/imm32/no-disp32
15840     0/imm32/output-is-write-only
15841     0x11/imm32/alloc-id:fake
15842     _Primitive-increment-ecx/imm32/next
15843 _Primitive-increment-ecx:  # (payload primitive)
15844     0x11/imm32/alloc-id:fake:payload
15845     # var/ecx <- increment => 41/increment-ecx
15846     0x11/imm32/alloc-id:fake
15847     _string-increment/imm32/name
15848     0/imm32/no-inouts
15849     0/imm32/no-inouts
15850     0x11/imm32/alloc-id:fake
15851     Single-int-var-in-ecx/imm32/outputs
15852     0x11/imm32/alloc-id:fake
15853     _string_41_increment_ecx/imm32/subx-name
15854     0/imm32/no-rm32
15855     0/imm32/no-r32
15856     0/imm32/no-imm32
15857     0/imm32/no-imm8
15858     0/imm32/no-disp32
15859     0/imm32/output-is-write-only
15860     0x11/imm32/alloc-id:fake
15861     _Primitive-increment-edx/imm32/next
15862 _Primitive-increment-edx:  # (payload primitive)
15863     0x11/imm32/alloc-id:fake:payload
15864     # var/edx <- increment => 42/increment-edx
15865     0x11/imm32/alloc-id:fake
15866     _string-increment/imm32/name
15867     0/imm32/no-inouts
15868     0/imm32/no-inouts
15869     0x11/imm32/alloc-id:fake
15870     Single-int-var-in-edx/imm32/outputs
15871     0x11/imm32/alloc-id:fake
15872     _string_42_increment_edx/imm32/subx-name
15873     0/imm32/no-rm32
15874     0/imm32/no-r32
15875     0/imm32/no-imm32
15876     0/imm32/no-imm8
15877     0/imm32/no-disp32
15878     0/imm32/output-is-write-only
15879     0x11/imm32/alloc-id:fake
15880     _Primitive-increment-ebx/imm32/next
15881 _Primitive-increment-ebx:  # (payload primitive)
15882     0x11/imm32/alloc-id:fake:payload
15883     # var/ebx <- increment => 43/increment-ebx
15884     0x11/imm32/alloc-id:fake
15885     _string-increment/imm32/name
15886     0/imm32/no-inouts
15887     0/imm32/no-inouts
15888     0x11/imm32/alloc-id:fake
15889     Single-int-var-in-ebx/imm32/outputs
15890     0x11/imm32/alloc-id:fake
15891     _string_43_increment_ebx/imm32/subx-name
15892     0/imm32/no-rm32
15893     0/imm32/no-r32
15894     0/imm32/no-imm32
15895     0/imm32/no-imm8
15896     0/imm32/no-disp32
15897     0/imm32/output-is-write-only
15898     0x11/imm32/alloc-id:fake
15899     _Primitive-increment-esi/imm32/next
15900 _Primitive-increment-esi:  # (payload primitive)
15901     0x11/imm32/alloc-id:fake:payload
15902     # var/esi <- increment => 46/increment-esi
15903     0x11/imm32/alloc-id:fake
15904     _string-increment/imm32/name
15905     0/imm32/no-inouts
15906     0/imm32/no-inouts
15907     0x11/imm32/alloc-id:fake
15908     Single-int-var-in-esi/imm32/outputs
15909     0x11/imm32/alloc-id:fake
15910     _string_46_increment_esi/imm32/subx-name
15911     0/imm32/no-rm32
15912     0/imm32/no-r32
15913     0/imm32/no-imm32
15914     0/imm32/no-imm8
15915     0/imm32/no-disp32
15916     0/imm32/output-is-write-only
15917     0x11/imm32/alloc-id:fake
15918     _Primitive-increment-edi/imm32/next
15919 _Primitive-increment-edi:  # (payload primitive)
15920     0x11/imm32/alloc-id:fake:payload
15921     # var/edi <- increment => 47/increment-edi
15922     0x11/imm32/alloc-id:fake
15923     _string-increment/imm32/name
15924     0/imm32/no-inouts
15925     0/imm32/no-inouts
15926     0x11/imm32/alloc-id:fake
15927     Single-int-var-in-edi/imm32/outputs
15928     0x11/imm32/alloc-id:fake
15929     _string_47_increment_edi/imm32/subx-name
15930     0/imm32/no-rm32
15931     0/imm32/no-r32
15932     0/imm32/no-imm32
15933     0/imm32/no-imm8
15934     0/imm32/no-disp32
15935     0/imm32/output-is-write-only
15936     0x11/imm32/alloc-id:fake
15937     _Primitive-decrement-eax/imm32/next
15938 _Primitive-decrement-eax:  # (payload primitive)
15939     0x11/imm32/alloc-id:fake:payload
15940     # var/eax <- decrement => 48/decrement-eax
15941     0x11/imm32/alloc-id:fake
15942     _string-decrement/imm32/name
15943     0/imm32/no-inouts
15944     0/imm32/no-inouts
15945     0x11/imm32/alloc-id:fake
15946     Single-int-var-in-eax/imm32/outputs
15947     0x11/imm32/alloc-id:fake
15948     _string_48_decrement_eax/imm32/subx-name
15949     0/imm32/no-rm32
15950     0/imm32/no-r32
15951     0/imm32/no-imm32
15952     0/imm32/no-imm8
15953     0/imm32/no-disp32
15954     0/imm32/output-is-write-only
15955     0x11/imm32/alloc-id:fake
15956     _Primitive-decrement-ecx/imm32/next
15957 _Primitive-decrement-ecx:  # (payload primitive)
15958     0x11/imm32/alloc-id:fake:payload
15959     # var/ecx <- decrement => 49/decrement-ecx
15960     0x11/imm32/alloc-id:fake
15961     _string-decrement/imm32/name
15962     0/imm32/no-inouts
15963     0/imm32/no-inouts
15964     0x11/imm32/alloc-id:fake
15965     Single-int-var-in-ecx/imm32/outputs
15966     0x11/imm32/alloc-id:fake
15967     _string_49_decrement_ecx/imm32/subx-name
15968     0/imm32/no-rm32
15969     0/imm32/no-r32
15970     0/imm32/no-imm32
15971     0/imm32/no-imm8
15972     0/imm32/no-disp32
15973     0/imm32/output-is-write-only
15974     0x11/imm32/alloc-id:fake
15975     _Primitive-decrement-edx/imm32/next
15976 _Primitive-decrement-edx:  # (payload primitive)
15977     0x11/imm32/alloc-id:fake:payload
15978     # var/edx <- decrement => 4a/decrement-edx
15979     0x11/imm32/alloc-id:fake
15980     _string-decrement/imm32/name
15981     0/imm32/no-inouts
15982     0/imm32/no-inouts
15983     0x11/imm32/alloc-id:fake
15984     Single-int-var-in-edx/imm32/outputs
15985     0x11/imm32/alloc-id:fake
15986     _string_4a_decrement_edx/imm32/subx-name
15987     0/imm32/no-rm32
15988     0/imm32/no-r32
15989     0/imm32/no-imm32
15990     0/imm32/no-imm8
15991     0/imm32/no-disp32
15992     0/imm32/output-is-write-only
15993     0x11/imm32/alloc-id:fake
15994     _Primitive-decrement-ebx/imm32/next
15995 _Primitive-decrement-ebx:  # (payload primitive)
15996     0x11/imm32/alloc-id:fake:payload
15997     # var/ebx <- decrement => 4b/decrement-ebx
15998     0x11/imm32/alloc-id:fake
15999     _string-decrement/imm32/name
16000     0/imm32/no-inouts
16001     0/imm32/no-inouts
16002     0x11/imm32/alloc-id:fake
16003     Single-int-var-in-ebx/imm32/outputs
16004     0x11/imm32/alloc-id:fake
16005     _string_4b_decrement_ebx/imm32/subx-name
16006     0/imm32/no-rm32
16007     0/imm32/no-r32
16008     0/imm32/no-imm32
16009     0/imm32/no-imm8
16010     0/imm32/no-disp32
16011     0/imm32/output-is-write-only
16012     0x11/imm32/alloc-id:fake
16013     _Primitive-decrement-esi/imm32/next
16014 _Primitive-decrement-esi:  # (payload primitive)
16015     0x11/imm32/alloc-id:fake:payload
16016     # var/esi <- decrement => 4e/decrement-esi
16017     0x11/imm32/alloc-id:fake
16018     _string-decrement/imm32/name
16019     0/imm32/no-inouts
16020     0/imm32/no-inouts
16021     0x11/imm32/alloc-id:fake
16022     Single-int-var-in-esi/imm32/outputs
16023     0x11/imm32/alloc-id:fake
16024     _string_4e_decrement_esi/imm32/subx-name
16025     0/imm32/no-rm32
16026     0/imm32/no-r32
16027     0/imm32/no-imm32
16028     0/imm32/no-imm8
16029     0/imm32/no-disp32
16030     0/imm32/output-is-write-only
16031     0x11/imm32/alloc-id:fake
16032     _Primitive-decrement-edi/imm32/next
16033 _Primitive-decrement-edi:  # (payload primitive)
16034     0x11/imm32/alloc-id:fake:payload
16035     # var/edi <- decrement => 4f/decrement-edi
16036     0x11/imm32/alloc-id:fake
16037     _string-decrement/imm32/name
16038     0/imm32/no-inouts
16039     0/imm32/no-inouts
16040     0x11/imm32/alloc-id:fake
16041     Single-int-var-in-edi/imm32/outputs
16042     0x11/imm32/alloc-id:fake
16043     _string_4f_decrement_edi/imm32/subx-name
16044     0/imm32/no-rm32
16045     0/imm32/no-r32
16046     0/imm32/no-imm32
16047     0/imm32/no-imm8
16048     0/imm32/no-disp32
16049     0/imm32/output-is-write-only
16050     0x11/imm32/alloc-id:fake
16051     _Primitive-increment-mem/imm32/next
16052 _Primitive-increment-mem:  # (payload primitive)
16053     0x11/imm32/alloc-id:fake:payload
16054     # increment var => ff 0/subop/increment *(ebp+__)
16055     0x11/imm32/alloc-id:fake
16056     _string-increment/imm32/name
16057     0x11/imm32/alloc-id:fake
16058     Single-int-var-in-mem/imm32/inouts
16059     0/imm32/no-outputs
16060     0/imm32/no-outputs
16061     0x11/imm32/alloc-id:fake
16062     _string_ff_subop_increment/imm32/subx-name
16063     1/imm32/rm32-is-first-inout
16064     0/imm32/no-r32
16065     0/imm32/no-imm32
16066     0/imm32/no-imm8
16067     0/imm32/no-disp32
16068     0/imm32/output-is-write-only
16069     0x11/imm32/alloc-id:fake
16070     _Primitive-increment-reg/imm32/next
16071 _Primitive-increment-reg:  # (payload primitive)
16072     0x11/imm32/alloc-id:fake:payload
16073     # var/reg <- increment => ff 0/subop/increment %__
16074     0x11/imm32/alloc-id:fake
16075     _string-increment/imm32/name
16076     0/imm32/no-inouts
16077     0/imm32/no-inouts
16078     0x11/imm32/alloc-id:fake
16079     Single-int-var-in-some-register/imm32/outputs
16080     0x11/imm32/alloc-id:fake
16081     _string_ff_subop_increment/imm32/subx-name
16082     3/imm32/rm32-is-first-output
16083     0/imm32/no-r32
16084     0/imm32/no-imm32
16085     0/imm32/no-imm8
16086     0/imm32/no-disp32
16087     0/imm32/output-is-write-only
16088     0x11/imm32/alloc-id:fake
16089     _Primitive-decrement-mem/imm32/next
16090 _Primitive-decrement-mem:  # (payload primitive)
16091     0x11/imm32/alloc-id:fake:payload
16092     # decrement var => ff 1/subop/decrement *(ebp+__)
16093     0x11/imm32/alloc-id:fake
16094     _string-decrement/imm32/name
16095     0x11/imm32/alloc-id:fake
16096     Single-int-var-in-mem/imm32/inouts
16097     0/imm32/no-outputs
16098     0/imm32/no-outputs
16099     0x11/imm32/alloc-id:fake
16100     _string_ff_subop_decrement/imm32/subx-name
16101     1/imm32/rm32-is-first-inout
16102     0/imm32/no-r32
16103     0/imm32/no-imm32
16104     0/imm32/no-imm8
16105     0/imm32/no-disp32
16106     0/imm32/output-is-write-only
16107     0x11/imm32/alloc-id:fake
16108     _Primitive-decrement-reg/imm32/next
16109 _Primitive-decrement-reg:  # (payload primitive)
16110     0x11/imm32/alloc-id:fake:payload
16111     # var/reg <- decrement => ff 1/subop/decrement %__
16112     0x11/imm32/alloc-id:fake
16113     _string-decrement/imm32/name
16114     0/imm32/no-inouts
16115     0/imm32/no-inouts
16116     0x11/imm32/alloc-id:fake
16117     Single-int-var-in-some-register/imm32/outputs
16118     0x11/imm32/alloc-id:fake
16119     _string_ff_subop_decrement/imm32/subx-name
16120     3/imm32/rm32-is-first-output
16121     0/imm32/no-r32
16122     0/imm32/no-imm32
16123     0/imm32/no-imm8
16124     0/imm32/no-disp32
16125     0/imm32/output-is-write-only
16126     0x11/imm32/alloc-id:fake
16127     _Primitive-add-to-eax/imm32/next
16128 # - add
16129 _Primitive-add-to-eax:  # (payload primitive)
16130     0x11/imm32/alloc-id:fake:payload
16131     # var/eax <- add lit => 05/add-to-eax lit/imm32
16132     0x11/imm32/alloc-id:fake
16133     _string-add/imm32/name
16134     0x11/imm32/alloc-id:fake
16135     Single-lit-var/imm32/inouts
16136     0x11/imm32/alloc-id:fake
16137     Single-int-var-in-eax/imm32/outputs
16138     0x11/imm32/alloc-id:fake
16139     _string_05_add_to_eax/imm32/subx-name
16140     0/imm32/no-rm32
16141     0/imm32/no-r32
16142     1/imm32/imm32-is-first-inout
16143     0/imm32/no-imm8
16144     0/imm32/no-disp32
16145     0/imm32/output-is-write-only
16146     0x11/imm32/alloc-id:fake
16147     _Primitive-add-reg-to-reg/imm32/next
16148 _Primitive-add-reg-to-reg:  # (payload primitive)
16149     0x11/imm32/alloc-id:fake:payload
16150     # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32
16151     0x11/imm32/alloc-id:fake
16152     _string-add/imm32/name
16153     0x11/imm32/alloc-id:fake
16154     Single-int-var-in-some-register/imm32/inouts
16155     0x11/imm32/alloc-id:fake
16156     Single-int-var-in-some-register/imm32/outputs
16157     0x11/imm32/alloc-id:fake
16158     _string_01_add_to/imm32/subx-name
16159     3/imm32/rm32-is-first-output
16160     1/imm32/r32-is-first-inout
16161     0/imm32/no-imm32
16162     0/imm32/no-imm8
16163     0/imm32/no-disp32
16164     0/imm32/output-is-write-only
16165     0x11/imm32/alloc-id:fake
16166     _Primitive-add-reg-to-mem/imm32/next
16167 _Primitive-add-reg-to-mem:  # (payload primitive)
16168     0x11/imm32/alloc-id:fake:payload
16169     # add-to var1 var2/reg => 01/add-to var1 var2/r32
16170     0x11/imm32/alloc-id:fake
16171     _string-add-to/imm32/name
16172     0x11/imm32/alloc-id:fake
16173     Two-args-int-stack-int-reg/imm32/inouts
16174     0/imm32/no-outputs
16175     0/imm32/no-outputs
16176     0x11/imm32/alloc-id:fake
16177     _string_01_add_to/imm32/subx-name
16178     1/imm32/rm32-is-first-inout
16179     2/imm32/r32-is-second-inout
16180     0/imm32/no-imm32
16181     0/imm32/no-imm8
16182     0/imm32/no-disp32
16183     0/imm32/output-is-write-only
16184     0x11/imm32/alloc-id:fake
16185     _Primitive-add-mem-to-reg/imm32/next
16186 _Primitive-add-mem-to-reg:  # (payload primitive)
16187     0x11/imm32/alloc-id:fake:payload
16188     # var1/reg <- add var2 => 03/add var2/rm32 var1/r32
16189     0x11/imm32/alloc-id:fake
16190     _string-add/imm32/name
16191     0x11/imm32/alloc-id:fake
16192     Single-int-var-in-mem/imm32/inouts
16193     0x11/imm32/alloc-id:fake
16194     Single-int-var-in-some-register/imm32/outputs
16195     0x11/imm32/alloc-id:fake
16196     _string_03_add/imm32/subx-name
16197     1/imm32/rm32-is-first-inout
16198     3/imm32/r32-is-first-output
16199     0/imm32/no-imm32
16200     0/imm32/no-imm8
16201     0/imm32/no-disp32
16202     0/imm32/output-is-write-only
16203     0x11/imm32/alloc-id:fake
16204     _Primitive-add-lit-to-reg/imm32/next
16205 _Primitive-add-lit-to-reg:  # (payload primitive)
16206     0x11/imm32/alloc-id:fake:payload
16207     # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32
16208     0x11/imm32/alloc-id:fake
16209     _string-add/imm32/name
16210     0x11/imm32/alloc-id:fake
16211     Single-lit-var/imm32/inouts
16212     0x11/imm32/alloc-id:fake
16213     Single-int-var-in-some-register/imm32/outputs
16214     0x11/imm32/alloc-id:fake
16215     _string_81_subop_add/imm32/subx-name
16216     3/imm32/rm32-is-first-output
16217     0/imm32/no-r32
16218     1/imm32/imm32-is-first-inout
16219     0/imm32/no-imm8
16220     0/imm32/no-disp32
16221     0/imm32/output-is-write-only
16222     0x11/imm32/alloc-id:fake
16223     _Primitive-add-lit-to-mem/imm32/next
16224 _Primitive-add-lit-to-mem:  # (payload primitive)
16225     0x11/imm32/alloc-id:fake:payload
16226     # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32
16227     0x11/imm32/alloc-id:fake
16228     _string-add-to/imm32/name
16229     0x11/imm32/alloc-id:fake
16230     Int-var-and-literal/imm32/inouts
16231     0/imm32/no-outputs
16232     0/imm32/no-outputs
16233     0x11/imm32/alloc-id:fake
16234     _string_81_subop_add/imm32/subx-name
16235     1/imm32/rm32-is-first-inout
16236     0/imm32/no-r32
16237     2/imm32/imm32-is-second-inout
16238     0/imm32/no-imm8
16239     0/imm32/no-disp32
16240     0/imm32/output-is-write-only
16241     0x11/imm32/alloc-id:fake
16242     _Primitive-subtract-from-eax/imm32/next
16243 # - subtract
16244 _Primitive-subtract-from-eax:  # (payload primitive)
16245     0x11/imm32/alloc-id:fake:payload
16246     # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32
16247     0x11/imm32/alloc-id:fake
16248     _string-subtract/imm32/name
16249     0x11/imm32/alloc-id:fake
16250     Single-lit-var/imm32/inouts
16251     0x11/imm32/alloc-id:fake
16252     Single-int-var-in-eax/imm32/outputs
16253     0x11/imm32/alloc-id:fake
16254     _string_2d_subtract_from_eax/imm32/subx-name
16255     0/imm32/no-rm32
16256     0/imm32/no-r32
16257     1/imm32/imm32-is-first-inout
16258     0/imm32/no-imm8
16259     0/imm32/no-disp32
16260     0/imm32/output-is-write-only
16261     0x11/imm32/alloc-id:fake
16262     _Primitive-subtract-reg-from-reg/imm32/next
16263 _Primitive-subtract-reg-from-reg:  # (payload primitive)
16264     0x11/imm32/alloc-id:fake:payload
16265     # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32
16266     0x11/imm32/alloc-id:fake
16267     _string-subtract/imm32/name
16268     0x11/imm32/alloc-id:fake
16269     Single-int-var-in-some-register/imm32/inouts
16270     0x11/imm32/alloc-id:fake
16271     Single-int-var-in-some-register/imm32/outputs
16272     0x11/imm32/alloc-id:fake
16273     _string_29_subtract_from/imm32/subx-name
16274     3/imm32/rm32-is-first-output
16275     1/imm32/r32-is-first-inout
16276     0/imm32/no-imm32
16277     0/imm32/no-imm8
16278     0/imm32/no-disp32
16279     0/imm32/output-is-write-only
16280     0x11/imm32/alloc-id:fake
16281     _Primitive-subtract-reg-from-mem/imm32/next
16282 _Primitive-subtract-reg-from-mem:  # (payload primitive)
16283     0x11/imm32/alloc-id:fake:payload
16284     # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32
16285     0x11/imm32/alloc-id:fake
16286     _string-subtract-from/imm32/name
16287     0x11/imm32/alloc-id:fake
16288     Two-args-int-stack-int-reg/imm32/inouts
16289     0/imm32/no-outputs
16290     0/imm32/no-outputs
16291     0x11/imm32/alloc-id:fake
16292     _string_29_subtract_from/imm32/subx-name
16293     1/imm32/rm32-is-first-inout
16294     2/imm32/r32-is-second-inout
16295     0/imm32/no-imm32
16296     0/imm32/no-imm8
16297     0/imm32/no-disp32
16298     0/imm32/output-is-write-only
16299     0x11/imm32/alloc-id:fake
16300     _Primitive-subtract-mem-from-reg/imm32/next
16301 _Primitive-subtract-mem-from-reg:  # (payload primitive)
16302     0x11/imm32/alloc-id:fake:payload
16303     # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32
16304     0x11/imm32/alloc-id:fake
16305     _string-subtract/imm32/name
16306     0x11/imm32/alloc-id:fake
16307     Single-int-var-in-mem/imm32/inouts
16308     0x11/imm32/alloc-id:fake
16309     Single-int-var-in-some-register/imm32/outputs
16310     0x11/imm32/alloc-id:fake
16311     _string_2b_subtract/imm32/subx-name
16312     1/imm32/rm32-is-first-inout
16313     3/imm32/r32-is-first-output
16314     0/imm32/no-imm32
16315     0/imm32/no-imm8
16316     0/imm32/no-disp32
16317     0/imm32/output-is-write-only
16318     0x11/imm32/alloc-id:fake
16319     _Primitive-subtract-lit-from-reg/imm32/next
16320 _Primitive-subtract-lit-from-reg:  # (payload primitive)
16321     0x11/imm32/alloc-id:fake:payload
16322     # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32
16323     0x11/imm32/alloc-id:fake
16324     _string-subtract/imm32/name
16325     0x11/imm32/alloc-id:fake
16326     Single-lit-var/imm32/inouts
16327     0x11/imm32/alloc-id:fake
16328     Single-int-var-in-some-register/imm32/outputs
16329     0x11/imm32/alloc-id:fake
16330     _string_81_subop_subtract/imm32/subx-name
16331     3/imm32/rm32-is-first-output
16332     0/imm32/no-r32
16333     1/imm32/imm32-is-first-inout
16334     0/imm32/no-imm8
16335     0/imm32/no-disp32
16336     0/imm32/output-is-write-only
16337     0x11/imm32/alloc-id:fake
16338     _Primitive-subtract-lit-from-mem/imm32/next
16339 _Primitive-subtract-lit-from-mem:  # (payload primitive)
16340     0x11/imm32/alloc-id:fake:payload
16341     # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32
16342     0x11/imm32/alloc-id:fake
16343     _string-subtract-from/imm32/name
16344     0x11/imm32/alloc-id:fake
16345     Int-var-and-literal/imm32/inouts
16346     0/imm32/no-outputs
16347     0/imm32/no-outputs
16348     0x11/imm32/alloc-id:fake
16349     _string_81_subop_subtract/imm32/subx-name
16350     1/imm32/rm32-is-first-inout
16351     0/imm32/no-r32
16352     2/imm32/imm32-is-second-inout
16353     0/imm32/no-imm8
16354     0/imm32/no-disp32
16355     0/imm32/output-is-write-only
16356     0x11/imm32/alloc-id:fake
16357     _Primitive-and-with-eax/imm32/next
16358 # - and
16359 _Primitive-and-with-eax:  # (payload primitive)
16360     0x11/imm32/alloc-id:fake:payload
16361     # var/eax <- and lit => 25/and-with-eax lit/imm32
16362     0x11/imm32/alloc-id:fake
16363     _string-and/imm32/name
16364     0x11/imm32/alloc-id:fake
16365     Single-lit-var/imm32/inouts
16366     0x11/imm32/alloc-id:fake
16367     Single-int-var-in-eax/imm32/outputs
16368     0x11/imm32/alloc-id:fake
16369     _string_25_and_with_eax/imm32/subx-name
16370     0/imm32/no-rm32
16371     0/imm32/no-r32
16372     1/imm32/imm32-is-first-inout
16373     0/imm32/no-imm8
16374     0/imm32/no-disp32
16375     0/imm32/output-is-write-only
16376     0x11/imm32/alloc-id:fake
16377     _Primitive-and-reg-with-reg/imm32/next
16378 _Primitive-and-reg-with-reg:  # (payload primitive)
16379     0x11/imm32/alloc-id:fake:payload
16380     # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32
16381     0x11/imm32/alloc-id:fake
16382     _string-and/imm32/name
16383     0x11/imm32/alloc-id:fake
16384     Single-int-var-in-some-register/imm32/inouts
16385     0x11/imm32/alloc-id:fake
16386     Single-int-var-in-some-register/imm32/outputs
16387     0x11/imm32/alloc-id:fake
16388     _string_21_and_with/imm32/subx-name
16389     3/imm32/rm32-is-first-output
16390     1/imm32/r32-is-first-inout
16391     0/imm32/no-imm32
16392     0/imm32/no-imm8
16393     0/imm32/no-disp32
16394     0/imm32/output-is-write-only
16395     0x11/imm32/alloc-id:fake
16396     _Primitive-and-reg-with-mem/imm32/next
16397 _Primitive-and-reg-with-mem:  # (payload primitive)
16398     0x11/imm32/alloc-id:fake:payload
16399     # and-with var1 var2/reg => 21/and-with var1 var2/r32
16400     0x11/imm32/alloc-id:fake
16401     _string-and-with/imm32/name
16402     0x11/imm32/alloc-id:fake
16403     Two-args-int-stack-int-reg/imm32/inouts
16404     0/imm32/no-outputs
16405     0/imm32/no-outputs
16406     0x11/imm32/alloc-id:fake
16407     _string_21_and_with/imm32/subx-name
16408     1/imm32/rm32-is-first-inout
16409     2/imm32/r32-is-second-inout
16410     0/imm32/no-imm32
16411     0/imm32/no-imm8
16412     0/imm32/no-disp32
16413     0/imm32/output-is-write-only
16414     0x11/imm32/alloc-id:fake
16415     _Primitive-and-mem-with-reg/imm32/next
16416 _Primitive-and-mem-with-reg:  # (payload primitive)
16417     0x11/imm32/alloc-id:fake:payload
16418     # var1/reg <- and var2 => 23/and var2/rm32 var1/r32
16419     0x11/imm32/alloc-id:fake
16420     _string-and/imm32/name
16421     0x11/imm32/alloc-id:fake
16422     Single-int-var-in-mem/imm32/inouts
16423     0x11/imm32/alloc-id:fake
16424     Single-int-var-in-some-register/imm32/outputs
16425     0x11/imm32/alloc-id:fake
16426     _string_23_and/imm32/subx-name
16427     1/imm32/rm32-is-first-inout
16428     3/imm32/r32-is-first-output
16429     0/imm32/no-imm32
16430     0/imm32/no-imm8
16431     0/imm32/no-disp32
16432     0/imm32/output-is-write-only
16433     0x11/imm32/alloc-id:fake
16434     _Primitive-and-lit-with-reg/imm32/next
16435 _Primitive-and-lit-with-reg:  # (payload primitive)
16436     0x11/imm32/alloc-id:fake:payload
16437     # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32
16438     0x11/imm32/alloc-id:fake
16439     _string-and/imm32/name
16440     0x11/imm32/alloc-id:fake
16441     Single-lit-var/imm32/inouts
16442     0x11/imm32/alloc-id:fake
16443     Single-int-var-in-some-register/imm32/outputs
16444     0x11/imm32/alloc-id:fake
16445     _string_81_subop_and/imm32/subx-name
16446     3/imm32/rm32-is-first-output
16447     0/imm32/no-r32
16448     1/imm32/imm32-is-first-inout
16449     0/imm32/no-imm8
16450     0/imm32/no-disp32
16451     0/imm32/output-is-write-only
16452     0x11/imm32/alloc-id:fake
16453     _Primitive-and-lit-with-mem/imm32/next
16454 _Primitive-and-lit-with-mem:  # (payload primitive)
16455     0x11/imm32/alloc-id:fake:payload
16456     # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32
16457     0x11/imm32/alloc-id:fake
16458     _string-and-with/imm32/name
16459     0x11/imm32/alloc-id:fake
16460     Int-var-and-literal/imm32/inouts
16461     0/imm32/no-outputs
16462     0/imm32/no-outputs
16463     0x11/imm32/alloc-id:fake
16464     _string_81_subop_and/imm32/subx-name
16465     1/imm32/rm32-is-first-inout
16466     0/imm32/no-r32
16467     2/imm32/imm32-is-second-inout
16468     0/imm32/no-imm8
16469     0/imm32/no-disp32
16470     0/imm32/output-is-write-only
16471     0x11/imm32/alloc-id:fake
16472     _Primitive-or-with-eax/imm32/next
16473 # - or
16474 _Primitive-or-with-eax:  # (payload primitive)
16475     0x11/imm32/alloc-id:fake:payload
16476     # var/eax <- or lit => 0d/or-with-eax lit/imm32
16477     0x11/imm32/alloc-id:fake
16478     _string-or/imm32/name
16479     0x11/imm32/alloc-id:fake
16480     Single-lit-var/imm32/inouts
16481     0x11/imm32/alloc-id:fake
16482     Single-int-var-in-eax/imm32/outputs
16483     0x11/imm32/alloc-id:fake
16484     _string_0d_or_with_eax/imm32/subx-name
16485     0/imm32/no-rm32
16486     0/imm32/no-r32
16487     1/imm32/imm32-is-first-inout
16488     0/imm32/no-imm8
16489     0/imm32/no-disp32
16490     0/imm32/output-is-write-only
16491     0x11/imm32/alloc-id:fake
16492     _Primitive-or-reg-with-reg/imm32/next
16493 _Primitive-or-reg-with-reg:  # (payload primitive)
16494     0x11/imm32/alloc-id:fake:payload
16495     # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32
16496     0x11/imm32/alloc-id:fake
16497     _string-or/imm32/name
16498     0x11/imm32/alloc-id:fake
16499     Single-int-var-in-some-register/imm32/inouts
16500     0x11/imm32/alloc-id:fake
16501     Single-int-var-in-some-register/imm32/outputs
16502     0x11/imm32/alloc-id:fake
16503     _string_09_or_with/imm32/subx-name
16504     3/imm32/rm32-is-first-output
16505     1/imm32/r32-is-first-inout
16506     0/imm32/no-imm32
16507     0/imm32/no-imm8
16508     0/imm32/no-disp32
16509     0/imm32/output-is-write-only
16510     0x11/imm32/alloc-id:fake
16511     _Primitive-or-reg-with-mem/imm32/next
16512 _Primitive-or-reg-with-mem:  # (payload primitive)
16513     0x11/imm32/alloc-id:fake:payload
16514     # or-with var1 var2/reg => 09/or-with var1 var2/r32
16515     0x11/imm32/alloc-id:fake
16516     _string-or-with/imm32/name
16517     0x11/imm32/alloc-id:fake
16518     Two-args-int-stack-int-reg/imm32/inouts
16519     0/imm32/no-outputs
16520     0/imm32/no-outputs
16521     0x11/imm32/alloc-id:fake
16522     _string_09_or_with/imm32/subx-name
16523     1/imm32/rm32-is-first-inout
16524     2/imm32/r32-is-second-inout
16525     0/imm32/no-imm32
16526     0/imm32/no-imm8
16527     0/imm32/no-disp32
16528     0/imm32/output-is-write-only
16529     0x11/imm32/alloc-id:fake
16530     _Primitive-or-mem-with-reg/imm32/next
16531 _Primitive-or-mem-with-reg:  # (payload primitive)
16532     0x11/imm32/alloc-id:fake:payload
16533     # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32
16534     0x11/imm32/alloc-id:fake
16535     _string-or/imm32/name
16536     0x11/imm32/alloc-id:fake
16537     Single-int-var-in-mem/imm32/inouts
16538     0x11/imm32/alloc-id:fake
16539     Single-int-var-in-some-register/imm32/outputs
16540     0x11/imm32/alloc-id:fake
16541     _string_0b_or/imm32/subx-name
16542     1/imm32/rm32-is-first-inout
16543     3/imm32/r32-is-first-output
16544     0/imm32/no-imm32
16545     0/imm32/no-imm8
16546     0/imm32/no-disp32
16547     0/imm32/output-is-write-only
16548     0x11/imm32/alloc-id:fake
16549     _Primitive-or-lit-with-reg/imm32/next
16550 _Primitive-or-lit-with-reg:  # (payload primitive)
16551     0x11/imm32/alloc-id:fake:payload
16552     # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32
16553     0x11/imm32/alloc-id:fake
16554     _string-or/imm32/name
16555     0x11/imm32/alloc-id:fake
16556     Single-lit-var/imm32/inouts
16557     0x11/imm32/alloc-id:fake
16558     Single-int-var-in-some-register/imm32/outputs
16559     0x11/imm32/alloc-id:fake
16560     _string_81_subop_or/imm32/subx-name
16561     3/imm32/rm32-is-first-output
16562     0/imm32/no-r32
16563     1/imm32/imm32-is-first-inout
16564     0/imm32/no-imm8
16565     0/imm32/no-disp32
16566     0/imm32/output-is-write-only
16567     0x11/imm32/alloc-id:fake
16568     _Primitive-or-lit-with-mem/imm32/next
16569 _Primitive-or-lit-with-mem:  # (payload primitive)
16570     0x11/imm32/alloc-id:fake:payload
16571     # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32
16572     0x11/imm32/alloc-id:fake
16573     _string-or-with/imm32/name
16574     0x11/imm32/alloc-id:fake
16575     Int-var-and-literal/imm32/inouts
16576     0/imm32/no-outputs
16577     0/imm32/no-outputs
16578     0x11/imm32/alloc-id:fake
16579     _string_81_subop_or/imm32/subx-name
16580     1/imm32/rm32-is-first-inout
16581     0/imm32/no-r32
16582     2/imm32/imm32-is-second-inout
16583     0/imm32/no-imm8
16584     0/imm32/no-disp32
16585     0/imm32/output-is-write-only
16586     0x11/imm32/alloc-id:fake
16587     _Primitive-xor-with-eax/imm32/next
16588 # - xor
16589 _Primitive-xor-with-eax:  # (payload primitive)
16590     0x11/imm32/alloc-id:fake:payload
16591     # var/eax <- xor lit => 35/xor-with-eax lit/imm32
16592     0x11/imm32/alloc-id:fake
16593     _string-xor/imm32/name
16594     0x11/imm32/alloc-id:fake
16595     Single-lit-var/imm32/inouts
16596     0x11/imm32/alloc-id:fake
16597     Single-int-var-in-eax/imm32/outputs
16598     0x11/imm32/alloc-id:fake
16599     _string_35_xor_with_eax/imm32/subx-name
16600     0/imm32/no-rm32
16601     0/imm32/no-r32
16602     1/imm32/imm32-is-first-inout
16603     0/imm32/no-imm8
16604     0/imm32/no-disp32
16605     0/imm32/output-is-write-only
16606     0x11/imm32/alloc-id:fake
16607     _Primitive-xor-reg-with-reg/imm32/next
16608 _Primitive-xor-reg-with-reg:  # (payload primitive)
16609     0x11/imm32/alloc-id:fake:payload
16610     # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32
16611     0x11/imm32/alloc-id:fake
16612     _string-xor/imm32/name
16613     0x11/imm32/alloc-id:fake
16614     Single-int-var-in-some-register/imm32/inouts
16615     0x11/imm32/alloc-id:fake
16616     Single-int-var-in-some-register/imm32/outputs
16617     0x11/imm32/alloc-id:fake
16618     _string_31_xor_with/imm32/subx-name
16619     3/imm32/rm32-is-first-output
16620     1/imm32/r32-is-first-inout
16621     0/imm32/no-imm32
16622     0/imm32/no-imm8
16623     0/imm32/no-disp32
16624     0/imm32/output-is-write-only
16625     0x11/imm32/alloc-id:fake
16626     _Primitive-xor-reg-with-mem/imm32/next
16627 _Primitive-xor-reg-with-mem:  # (payload primitive)
16628     0x11/imm32/alloc-id:fake:payload
16629     # xor-with var1 var2/reg => 31/xor-with var1 var2/r32
16630     0x11/imm32/alloc-id:fake
16631     _string-xor-with/imm32/name
16632     0x11/imm32/alloc-id:fake
16633     Two-args-int-stack-int-reg/imm32/inouts
16634     0/imm32/no-outputs
16635     0/imm32/no-outputs
16636     0x11/imm32/alloc-id:fake
16637     _string_31_xor_with/imm32/subx-name
16638     1/imm32/rm32-is-first-inout
16639     2/imm32/r32-is-second-inout
16640     0/imm32/no-imm32
16641     0/imm32/no-imm8
16642     0/imm32/no-disp32
16643     0/imm32/output-is-write-only
16644     0x11/imm32/alloc-id:fake
16645     _Primitive-xor-mem-with-reg/imm32/next
16646 _Primitive-xor-mem-with-reg:  # (payload primitive)
16647     0x11/imm32/alloc-id:fake:payload
16648     # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32
16649     0x11/imm32/alloc-id:fake
16650     _string-xor/imm32/name
16651     0x11/imm32/alloc-id:fake
16652     Single-int-var-in-mem/imm32/inouts
16653     0x11/imm32/alloc-id:fake
16654     Single-int-var-in-some-register/imm32/outputs
16655     0x11/imm32/alloc-id:fake
16656     _string_33_xor/imm32/subx-name
16657     1/imm32/rm32-is-first-inout
16658     3/imm32/r32-is-first-output
16659     0/imm32/no-imm32
16660     0/imm32/no-imm8
16661     0/imm32/no-disp32
16662     0/imm32/output-is-write-only
16663     0x11/imm32/alloc-id:fake
16664     _Primitive-xor-lit-with-reg/imm32/next
16665 _Primitive-xor-lit-with-reg:  # (payload primitive)
16666     0x11/imm32/alloc-id:fake:payload
16667     # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32
16668     0x11/imm32/alloc-id:fake
16669     _string-xor/imm32/name
16670     0x11/imm32/alloc-id:fake
16671     Single-lit-var/imm32/inouts
16672     0x11/imm32/alloc-id:fake
16673     Single-int-var-in-some-register/imm32/outputs
16674     0x11/imm32/alloc-id:fake
16675     _string_81_subop_xor/imm32/subx-name
16676     3/imm32/rm32-is-first-output
16677     0/imm32/no-r32
16678     1/imm32/imm32-is-first-inout
16679     0/imm32/no-imm8
16680     0/imm32/no-disp32
16681     0/imm32/output-is-write-only
16682     0x11/imm32/alloc-id:fake
16683     _Primitive-xor-lit-with-mem/imm32/next
16684 _Primitive-xor-lit-with-mem:  # (payload primitive)
16685     0x11/imm32/alloc-id:fake:payload
16686     # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32
16687     0x11/imm32/alloc-id:fake
16688     _string-xor-with/imm32/name
16689     0x11/imm32/alloc-id:fake
16690     Int-var-and-literal/imm32/inouts
16691     0/imm32/no-outputs
16692     0/imm32/no-outputs
16693     0x11/imm32/alloc-id:fake
16694     _string_81_subop_xor/imm32/subx-name
16695     1/imm32/rm32-is-first-inout
16696     0/imm32/no-r32
16697     2/imm32/imm32-is-second-inout
16698     0/imm32/no-imm8
16699     0/imm32/no-disp32
16700     0/imm32/output-is-write-only
16701     0x11/imm32/alloc-id:fake
16702     _Primitive-shift-reg-left-by-lit/imm32/next
16703 _Primitive-shift-reg-left-by-lit:  # (payload primitive)
16704     0x11/imm32/alloc-id:fake:payload
16705     # var1/reg <- shift-left lit => c1/shift 4/subop/left var1/rm32 lit/imm32
16706     0x11/imm32/alloc-id:fake
16707     _string-shift-left/imm32/name
16708     0x11/imm32/alloc-id:fake
16709     Single-lit-var/imm32/inouts
16710     0x11/imm32/alloc-id:fake
16711     Single-int-var-in-some-register/imm32/outputs
16712     0x11/imm32/alloc-id:fake
16713     _string_c1_subop_shift_left/imm32/subx-name
16714     3/imm32/rm32-is-first-output
16715     0/imm32/no-r32
16716     0/imm32/no-imm32
16717     1/imm32/imm8-is-first-inout
16718     0/imm32/no-disp32
16719     0/imm32/output-is-write-only
16720     0x11/imm32/alloc-id:fake
16721     _Primitive-shift-reg-right-by-lit/imm32/next
16722 _Primitive-shift-reg-right-by-lit:  # (payload primitive)
16723     0x11/imm32/alloc-id:fake:payload
16724     # var1/reg <- shift-right lit => c1/shift 5/subop/right var1/rm32 lit/imm32
16725     0x11/imm32/alloc-id:fake
16726     _string-shift-right/imm32/name
16727     0x11/imm32/alloc-id:fake
16728     Single-lit-var/imm32/inouts
16729     0x11/imm32/alloc-id:fake
16730     Single-int-var-in-some-register/imm32/outputs
16731     0x11/imm32/alloc-id:fake
16732     _string_c1_subop_shift_right_padding_zeroes/imm32/subx-name
16733     3/imm32/rm32-is-first-output
16734     0/imm32/no-r32
16735     0/imm32/no-imm32
16736     1/imm32/imm8-is-first-inout
16737     0/imm32/no-disp32
16738     0/imm32/output-is-write-only
16739     0x11/imm32/alloc-id:fake
16740     _Primitive-shift-reg-right-signed-by-lit/imm32/next
16741 _Primitive-shift-reg-right-signed-by-lit:  # (payload primitive)
16742     0x11/imm32/alloc-id:fake:payload
16743     # var1/reg <- shift-right-signed lit => c1/shift 7/subop/right-preserving-sign var1/rm32 lit/imm32
16744     0x11/imm32/alloc-id:fake
16745     _string-shift-right-signed/imm32/name
16746     0x11/imm32/alloc-id:fake
16747     Single-lit-var/imm32/inouts
16748     0x11/imm32/alloc-id:fake
16749     Single-int-var-in-some-register/imm32/outputs
16750     0x11/imm32/alloc-id:fake
16751     _string_c1_subop_shift_right_preserving_sign/imm32/subx-name
16752     3/imm32/rm32-is-first-output
16753     0/imm32/no-r32
16754     0/imm32/no-imm32
16755     1/imm32/imm8-is-first-inout
16756     0/imm32/no-disp32
16757     0/imm32/output-is-write-only
16758     0x11/imm32/alloc-id:fake
16759     _Primitive-shift-mem-left-by-lit/imm32/next
16760 _Primitive-shift-mem-left-by-lit:  # (payload primitive)
16761     0x11/imm32/alloc-id:fake:payload
16762     # shift-left var1, lit => c1/shift 4/subop/left var1/rm32 lit/imm32
16763     0x11/imm32/alloc-id:fake
16764     _string-shift-left/imm32/name
16765     0x11/imm32/alloc-id:fake
16766     Int-var-and-literal/imm32/inouts
16767     0/imm32/no-outputs
16768     0/imm32/no-outputs
16769     0x11/imm32/alloc-id:fake
16770     _string_c1_subop_shift_left/imm32/subx-name
16771     1/imm32/rm32-is-first-inout
16772     0/imm32/no-r32
16773     0/imm32/no-imm32
16774     2/imm32/imm8-is-second-inout
16775     0/imm32/no-disp32
16776     0/imm32/output-is-write-only
16777     0x11/imm32/alloc-id:fake
16778     _Primitive-shift-mem-right-by-lit/imm32/next
16779 _Primitive-shift-mem-right-by-lit:  # (payload primitive)
16780     0x11/imm32/alloc-id:fake:payload
16781     # shift-right var1, lit => c1/shift 5/subop/right var1/rm32 lit/imm32
16782     0x11/imm32/alloc-id:fake
16783     _string-shift-right/imm32/name
16784     0x11/imm32/alloc-id:fake
16785     Int-var-and-literal/imm32/inouts
16786     0/imm32/no-outputs
16787     0/imm32/no-outputs
16788     0x11/imm32/alloc-id:fake
16789     _string_c1_subop_shift_right_padding_zeroes/imm32/subx-name
16790     1/imm32/rm32-is-first-inout
16791     0/imm32/no-r32
16792     0/imm32/no-imm32
16793     2/imm32/imm8-is-second-inout
16794     0/imm32/no-disp32
16795     0/imm32/output-is-write-only
16796     0x11/imm32/alloc-id:fake
16797     _Primitive-shift-mem-right-signed-by-lit/imm32/next
16798 _Primitive-shift-mem-right-signed-by-lit:  # (payload primitive)
16799     0x11/imm32/alloc-id:fake:payload
16800     # shift-right-signed var1, lit => c1/shift 7/subop/right-preserving-sign var1/rm32 lit/imm32
16801     0x11/imm32/alloc-id:fake
16802     _string-shift-right-signed/imm32/name
16803     0x11/imm32/alloc-id:fake
16804     Int-var-and-literal/imm32/inouts
16805     0/imm32/no-outputs
16806     0/imm32/no-outputs
16807     0x11/imm32/alloc-id:fake
16808     _string_c1_subop_shift_right_preserving_sign/imm32/subx-name
16809     1/imm32/rm32-is-first-inout
16810     0/imm32/no-r32
16811     0/imm32/no-imm32
16812     2/imm32/imm8-is-second-inout
16813     0/imm32/no-disp32
16814     0/imm32/output-is-write-only
16815     0x11/imm32/alloc-id:fake
16816     _Primitive-copy-to-eax/imm32/next
16817 # - copy
16818 _Primitive-copy-to-eax:  # (payload primitive)
16819     0x11/imm32/alloc-id:fake:payload
16820     # var/eax <- copy lit => b8/copy-to-eax lit/imm32
16821     0x11/imm32/alloc-id:fake
16822     _string-copy/imm32/name
16823     0x11/imm32/alloc-id:fake
16824     Single-lit-var/imm32/inouts
16825     0x11/imm32/alloc-id:fake
16826     Single-int-var-in-eax/imm32/outputs
16827     0x11/imm32/alloc-id:fake
16828     _string_b8_copy_to_eax/imm32/subx-name
16829     0/imm32/no-rm32
16830     0/imm32/no-r32
16831     1/imm32/imm32-is-first-inout
16832     0/imm32/no-imm8
16833     0/imm32/no-disp32
16834     1/imm32/output-is-write-only
16835     0x11/imm32/alloc-id:fake
16836     _Primitive-copy-to-ecx/imm32/next
16837 _Primitive-copy-to-ecx:  # (payload primitive)
16838     0x11/imm32/alloc-id:fake:payload
16839     # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32
16840     0x11/imm32/alloc-id:fake
16841     _string-copy/imm32/name
16842     0x11/imm32/alloc-id:fake
16843     Single-lit-var/imm32/inouts
16844     0x11/imm32/alloc-id:fake
16845     Single-int-var-in-ecx/imm32/outputs
16846     0x11/imm32/alloc-id:fake
16847     _string_b9_copy_to_ecx/imm32/subx-name
16848     0/imm32/no-rm32
16849     0/imm32/no-r32
16850     1/imm32/imm32-is-first-inout
16851     0/imm32/no-imm8
16852     0/imm32/no-disp32
16853     1/imm32/output-is-write-only
16854     0x11/imm32/alloc-id:fake
16855     _Primitive-copy-to-edx/imm32/next
16856 _Primitive-copy-to-edx:  # (payload primitive)
16857     0x11/imm32/alloc-id:fake:payload
16858     # var/edx <- copy lit => ba/copy-to-edx lit/imm32
16859     0x11/imm32/alloc-id:fake
16860     _string-copy/imm32/name
16861     0x11/imm32/alloc-id:fake
16862     Single-lit-var/imm32/inouts
16863     0x11/imm32/alloc-id:fake
16864     Single-int-var-in-edx/imm32/outputs
16865     0x11/imm32/alloc-id:fake
16866     _string_ba_copy_to_edx/imm32/subx-name
16867     0/imm32/no-rm32
16868     0/imm32/no-r32
16869     1/imm32/imm32-is-first-inout
16870     0/imm32/no-imm8
16871     0/imm32/no-disp32
16872     1/imm32/output-is-write-only
16873     0x11/imm32/alloc-id:fake
16874     _Primitive-copy-to-ebx/imm32/next
16875 _Primitive-copy-to-ebx:  # (payload primitive)
16876     0x11/imm32/alloc-id:fake:payload
16877     # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32
16878     0x11/imm32/alloc-id:fake
16879     _string-copy/imm32/name
16880     0x11/imm32/alloc-id:fake
16881     Single-lit-var/imm32/inouts
16882     0x11/imm32/alloc-id:fake
16883     Single-int-var-in-ebx/imm32/outputs
16884     0x11/imm32/alloc-id:fake
16885     _string_bb_copy_to_ebx/imm32/subx-name
16886     0/imm32/no-rm32
16887     0/imm32/no-r32
16888     1/imm32/imm32-is-first-inout
16889     0/imm32/no-imm8
16890     0/imm32/no-disp32
16891     1/imm32/output-is-write-only
16892     0x11/imm32/alloc-id:fake
16893     _Primitive-copy-to-esi/imm32/next
16894 _Primitive-copy-to-esi:  # (payload primitive)
16895     0x11/imm32/alloc-id:fake:payload
16896     # var/esi <- copy lit => be/copy-to-esi lit/imm32
16897     0x11/imm32/alloc-id:fake
16898     _string-copy/imm32/name
16899     0x11/imm32/alloc-id:fake
16900     Single-lit-var/imm32/inouts
16901     0x11/imm32/alloc-id:fake
16902     Single-int-var-in-esi/imm32/outputs
16903     0x11/imm32/alloc-id:fake
16904     _string_be_copy_to_esi/imm32/subx-name
16905     0/imm32/no-rm32
16906     0/imm32/no-r32
16907     1/imm32/imm32-is-first-inout
16908     0/imm32/no-imm8
16909     0/imm32/no-disp32
16910     1/imm32/output-is-write-only
16911     0x11/imm32/alloc-id:fake
16912     _Primitive-copy-to-edi/imm32/next
16913 _Primitive-copy-to-edi:  # (payload primitive)
16914     0x11/imm32/alloc-id:fake:payload
16915     # var/edi <- copy lit => bf/copy-to-edi lit/imm32
16916     0x11/imm32/alloc-id:fake
16917     _string-copy/imm32/name
16918     0x11/imm32/alloc-id:fake
16919     Single-lit-var/imm32/inouts
16920     0x11/imm32/alloc-id:fake
16921     Single-int-var-in-edi/imm32/outputs
16922     0x11/imm32/alloc-id:fake
16923     _string_bf_copy_to_edi/imm32/subx-name
16924     0/imm32/no-rm32
16925     0/imm32/no-r32
16926     1/imm32/imm32-is-first-inout
16927     0/imm32/no-imm8
16928     0/imm32/no-disp32
16929     1/imm32/output-is-write-only
16930     0x11/imm32/alloc-id:fake
16931     _Primitive-copy-reg-to-reg/imm32/next
16932 _Primitive-copy-reg-to-reg:  # (payload primitive)
16933     0x11/imm32/alloc-id:fake:payload
16934     # var1/reg <- copy var2/reg => 89/<- var1/rm32 var2/r32
16935     0x11/imm32/alloc-id:fake
16936     _string-copy/imm32/name
16937     0x11/imm32/alloc-id:fake
16938     Single-int-var-in-some-register/imm32/inouts
16939     0x11/imm32/alloc-id:fake
16940     Single-int-var-in-some-register/imm32/outputs
16941     0x11/imm32/alloc-id:fake
16942     _string_89_<-/imm32/subx-name
16943     3/imm32/rm32-is-first-output
16944     1/imm32/r32-is-first-inout
16945     0/imm32/no-imm32
16946     0/imm32/no-imm8
16947     0/imm32/no-disp32
16948     1/imm32/output-is-write-only
16949     0x11/imm32/alloc-id:fake
16950     _Primitive-copy-reg-to-mem/imm32/next
16951 _Primitive-copy-reg-to-mem:  # (payload primitive)
16952     0x11/imm32/alloc-id:fake:payload
16953     # copy-to var1 var2/reg => 89/<- var1 var2/r32
16954     0x11/imm32/alloc-id:fake
16955     _string-copy-to/imm32/name
16956     0x11/imm32/alloc-id:fake
16957     Two-args-int-stack-int-reg/imm32/inouts
16958     0/imm32/no-outputs
16959     0/imm32/no-outputs
16960     0x11/imm32/alloc-id:fake
16961     _string_89_<-/imm32/subx-name
16962     1/imm32/rm32-is-first-inout
16963     2/imm32/r32-is-second-inout
16964     0/imm32/no-imm32
16965     0/imm32/no-imm8
16966     0/imm32/no-disp32
16967     1/imm32/output-is-write-only
16968     0x11/imm32/alloc-id:fake
16969     _Primitive-copy-mem-to-reg/imm32/next
16970 _Primitive-copy-mem-to-reg:  # (payload primitive)
16971     0x11/imm32/alloc-id:fake:payload
16972     # var1/reg <- copy var2 => 8b/-> var2/rm32 var1/r32
16973     0x11/imm32/alloc-id:fake
16974     _string-copy/imm32/name
16975     0x11/imm32/alloc-id:fake
16976     Single-int-var-in-mem/imm32/inouts
16977     0x11/imm32/alloc-id:fake
16978     Single-int-var-in-some-register/imm32/outputs
16979     0x11/imm32/alloc-id:fake
16980     _string_8b_->/imm32/subx-name
16981     1/imm32/rm32-is-first-inout
16982     3/imm32/r32-is-first-output
16983     0/imm32/no-imm32
16984     0/imm32/no-imm8
16985     0/imm32/no-disp32
16986     1/imm32/output-is-write-only
16987     0x11/imm32/alloc-id:fake
16988     _Primitive-copy-lit-to-reg/imm32/next
16989 _Primitive-copy-lit-to-reg:  # (payload primitive)
16990     0x11/imm32/alloc-id:fake:payload
16991     # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32
16992     0x11/imm32/alloc-id:fake
16993     _string-copy/imm32/name
16994     0x11/imm32/alloc-id:fake
16995     Single-lit-var/imm32/inouts
16996     0x11/imm32/alloc-id:fake
16997     Single-int-var-in-some-register/imm32/outputs
16998     0x11/imm32/alloc-id:fake
16999     _string_c7_subop_copy/imm32/subx-name
17000     3/imm32/rm32-is-first-output
17001     0/imm32/no-r32
17002     1/imm32/imm32-is-first-inout
17003     0/imm32/no-imm8
17004     0/imm32/no-disp32
17005     1/imm32/output-is-write-only
17006     0x11/imm32/alloc-id:fake
17007     _Primitive-copy-lit-to-mem/imm32/next
17008 _Primitive-copy-lit-to-mem:  # (payload primitive)
17009     0x11/imm32/alloc-id:fake:payload
17010     # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32
17011     0x11/imm32/alloc-id:fake
17012     _string-copy-to/imm32/name
17013     0x11/imm32/alloc-id:fake
17014     Int-var-and-literal/imm32/inouts
17015     0/imm32/no-outputs
17016     0/imm32/no-outputs
17017     0x11/imm32/alloc-id:fake
17018     _string_c7_subop_copy/imm32/subx-name
17019     1/imm32/rm32-is-first-inout
17020     0/imm32/no-r32
17021     2/imm32/imm32-is-second-inout
17022     0/imm32/no-imm8
17023     0/imm32/no-disp32
17024     1/imm32/output-is-write-only
17025     0x11/imm32/alloc-id:fake
17026     _Primitive-copy-byte-from-reg/imm32/next
17027 # - copy byte
17028 _Primitive-copy-byte-from-reg:
17029     0x11/imm32/alloc-id:fake:payload
17030     # var/reg <- copy-byte var2/reg2 => 8a/byte-> %var2 var/r32
17031     0x11/imm32/alloc-id:fake
17032     _string-copy-byte/imm32/name
17033     0x11/imm32/alloc-id:fake
17034     Single-byte-var-in-some-register/imm32/inouts
17035     0x11/imm32/alloc-id:fake
17036     Single-byte-var-in-some-register/imm32/outputs
17037     0x11/imm32/alloc-id:fake
17038     _string_8a_copy_byte/imm32/subx-name
17039     1/imm32/rm32-is-first-inout
17040     3/imm32/r32-is-first-output
17041     0/imm32/no-imm32
17042     0/imm32/no-imm8
17043     0/imm32/no-disp32
17044     1/imm32/output-is-write-only
17045     0x11/imm32/alloc-id:fake
17046     _Primitive-copy-byte-from-mem/imm32/next
17047 _Primitive-copy-byte-from-mem:
17048     0x11/imm32/alloc-id:fake:payload
17049     # var/reg <- copy-byte *var2/reg2 => 8a/byte-> *var2 var/r32
17050     0x11/imm32/alloc-id:fake
17051     _string-copy-byte/imm32/name
17052     0x11/imm32/alloc-id:fake
17053     Single-byte-var-in-mem/imm32/inouts
17054     0x11/imm32/alloc-id:fake
17055     Single-byte-var-in-some-register/imm32/outputs
17056     0x11/imm32/alloc-id:fake
17057     _string_8a_copy_byte/imm32/subx-name
17058     1/imm32/rm32-is-first-inout
17059     3/imm32/r32-is-first-output
17060     0/imm32/no-imm32
17061     0/imm32/no-imm8
17062     0/imm32/no-disp32
17063     1/imm32/output-is-write-only
17064     0x11/imm32/alloc-id:fake
17065     _Primitive-copy-byte-to-mem/imm32/next
17066 _Primitive-copy-byte-to-mem:
17067     0x11/imm32/alloc-id:fake:payload
17068     # copy-byte-to *var1/reg1, var2/reg2 => 88/byte<- *reg1 reg2/r32
17069     0x11/imm32/alloc-id:fake
17070     _string-copy-byte-to/imm32/name
17071     0x11/imm32/alloc-id:fake
17072     Two-args-byte-stack-byte-reg/imm32/inouts
17073     0/imm32/no-outputs
17074     0/imm32/no-outputs
17075     0x11/imm32/alloc-id:fake
17076     _string_88_copy_byte/imm32/subx-name
17077     1/imm32/rm32-is-first-inout
17078     2/imm32/r32-is-second-inout
17079     0/imm32/no-imm32
17080     0/imm32/no-imm8
17081     0/imm32/no-disp32
17082     0/imm32/output-is-write-only
17083     0x11/imm32/alloc-id:fake
17084     _Primitive-address/imm32/next
17085 # - address
17086 _Primitive-address:  # (payload primitive)
17087     0x11/imm32/alloc-id:fake:payload
17088     # var1/reg <- address var2 => 8d/copy-address var2/rm32 var1/r32
17089     0x11/imm32/alloc-id:fake
17090     _string-address/imm32/name
17091     0x11/imm32/alloc-id:fake
17092     Single-int-var-in-mem/imm32/inouts
17093     0x11/imm32/alloc-id:fake
17094     Single-addr-var-in-some-register/imm32/outputs
17095     0x11/imm32/alloc-id:fake
17096     _string_8d_copy_address/imm32/subx-name
17097     1/imm32/rm32-is-first-inout
17098     3/imm32/r32-is-first-output
17099     0/imm32/no-imm32
17100     0/imm32/no-imm8
17101     0/imm32/no-disp32
17102     1/imm32/output-is-write-only
17103     0x11/imm32/alloc-id:fake
17104     _Primitive-compare-reg-with-reg/imm32/next
17105 # - compare
17106 _Primitive-compare-reg-with-reg:  # (payload primitive)
17107     0x11/imm32/alloc-id:fake:payload
17108     # compare var1/reg1 var2/reg2 => 39/compare var1/rm32 var2/r32
17109     0x11/imm32/alloc-id:fake
17110     _string-compare/imm32/name
17111     0x11/imm32/alloc-id:fake
17112     Two-int-args-in-regs/imm32/inouts
17113     0/imm32/no-outputs
17114     0/imm32/no-outputs
17115     0x11/imm32/alloc-id:fake
17116     _string_39_compare->/imm32/subx-name
17117     1/imm32/rm32-is-first-inout
17118     2/imm32/r32-is-second-inout
17119     0/imm32/no-imm32
17120     0/imm32/no-imm8
17121     0/imm32/no-disp32
17122     0/imm32/output-is-write-only
17123     0x11/imm32/alloc-id:fake
17124     _Primitive-compare-mem-with-reg/imm32/next
17125 _Primitive-compare-mem-with-reg:  # (payload primitive)
17126     0x11/imm32/alloc-id:fake:payload
17127     # compare var1 var2/reg => 39/compare var1/rm32 var2/r32
17128     0x11/imm32/alloc-id:fake
17129     _string-compare/imm32/name
17130     0x11/imm32/alloc-id:fake
17131     Two-args-int-stack-int-reg/imm32/inouts
17132     0/imm32/no-outputs
17133     0/imm32/no-outputs
17134     0x11/imm32/alloc-id:fake
17135     _string_39_compare->/imm32/subx-name
17136     1/imm32/rm32-is-first-inout
17137     2/imm32/r32-is-second-inout
17138     0/imm32/no-imm32
17139     0/imm32/no-imm8
17140     0/imm32/no-disp32
17141     0/imm32/output-is-write-only
17142     0x11/imm32/alloc-id:fake
17143     _Primitive-compare-reg-with-mem/imm32/next
17144 _Primitive-compare-reg-with-mem:  # (payload primitive)
17145     0x11/imm32/alloc-id:fake:payload
17146     # compare var1/reg var2 => 3b/compare<- var2/rm32 var1/r32
17147     0x11/imm32/alloc-id:fake
17148     _string-compare/imm32/name
17149     0x11/imm32/alloc-id:fake
17150     Two-args-int-reg-int-stack/imm32/inouts
17151     0/imm32/no-outputs
17152     0/imm32/no-outputs
17153     0x11/imm32/alloc-id:fake
17154     _string_3b_compare<-/imm32/subx-name
17155     2/imm32/rm32-is-second-inout
17156     1/imm32/r32-is-first-inout
17157     0/imm32/no-imm32
17158     0/imm32/no-imm8
17159     0/imm32/no-disp32
17160     0/imm32/output-is-write-only
17161     0x11/imm32/alloc-id:fake
17162     _Primitive-compare-eax-with-literal/imm32/next
17163 _Primitive-compare-eax-with-literal:  # (payload primitive)
17164     0x11/imm32/alloc-id:fake:payload
17165     # compare var1/eax n => 3d/compare-eax-with n/imm32
17166     0x11/imm32/alloc-id:fake
17167     _string-compare/imm32/name
17168     0x11/imm32/alloc-id:fake
17169     Two-args-int-eax-int-literal/imm32/inouts
17170     0/imm32/no-outputs
17171     0/imm32/no-outputs
17172     0x11/imm32/alloc-id:fake
17173     _string_3d_compare_eax_with/imm32/subx-name
17174     0/imm32/no-rm32
17175     0/imm32/no-r32
17176     2/imm32/imm32-is-second-inout
17177     0/imm32/no-imm8
17178     0/imm32/no-disp32
17179     0/imm32/output-is-write-only
17180     0x11/imm32/alloc-id:fake
17181     _Primitive-compare-reg-with-literal/imm32/next
17182 _Primitive-compare-reg-with-literal:  # (payload primitive)
17183     0x11/imm32/alloc-id:fake:payload
17184     # compare var1/reg n => 81 7/subop/compare %reg n/imm32
17185     0x11/imm32/alloc-id:fake
17186     _string-compare/imm32/name
17187     0x11/imm32/alloc-id:fake
17188     Int-var-in-register-and-literal/imm32/inouts
17189     0/imm32/no-outputs
17190     0/imm32/no-outputs
17191     0x11/imm32/alloc-id:fake
17192     _string_81_subop_compare/imm32/subx-name
17193     1/imm32/rm32-is-first-inout
17194     0/imm32/no-r32
17195     2/imm32/imm32-is-second-inout
17196     0/imm32/no-imm8
17197     0/imm32/no-disp32
17198     0/imm32/output-is-write-only
17199     0x11/imm32/alloc-id:fake
17200     _Primitive-compare-mem-with-literal/imm32/next
17201 _Primitive-compare-mem-with-literal:  # (payload primitive)
17202     0x11/imm32/alloc-id:fake:payload
17203     # compare var1 n => 81 7/subop/compare *(ebp+___) n/imm32
17204     0x11/imm32/alloc-id:fake
17205     _string-compare/imm32/name
17206     0x11/imm32/alloc-id:fake
17207     Int-var-and-literal/imm32/inouts
17208     0/imm32/no-outputs
17209     0/imm32/no-outputs
17210     0x11/imm32/alloc-id:fake
17211     _string_81_subop_compare/imm32/subx-name
17212     1/imm32/rm32-is-first-inout
17213     0/imm32/no-r32
17214     2/imm32/imm32-is-second-inout
17215     0/imm32/no-imm8
17216     0/imm32/no-disp32
17217     0/imm32/output-is-write-only
17218     0x11/imm32/alloc-id:fake
17219     _Primitive-multiply-reg-by-reg/imm32/next
17220 # - multiply
17221 _Primitive-multiply-reg-by-reg:  # (payload primitive)
17222     0x11/imm32/alloc-id:fake:payload
17223     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
17224     0x11/imm32/alloc-id:fake
17225     _string-multiply/imm32/name
17226     0x11/imm32/alloc-id:fake
17227     Single-int-var-in-some-register/imm32/inouts
17228     0x11/imm32/alloc-id:fake
17229     Single-int-var-in-some-register/imm32/outputs
17230     0x11/imm32/alloc-id:fake
17231     _string_0f_af_multiply/imm32/subx-name
17232     1/imm32/rm32-is-first-inout
17233     3/imm32/r32-is-first-output
17234     0/imm32/no-imm32
17235     0/imm32/no-imm8
17236     0/imm32/no-disp32
17237     0/imm32/output-is-write-only
17238     0x11/imm32/alloc-id:fake
17239     _Primitive-multiply-reg-by-mem/imm32/next
17240 _Primitive-multiply-reg-by-mem:  # (payload primitive)
17241     0x11/imm32/alloc-id:fake:payload
17242     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
17243     0x11/imm32/alloc-id:fake
17244     _string-multiply/imm32/name
17245     0x11/imm32/alloc-id:fake
17246     Single-int-var-in-mem/imm32/inouts
17247     0x11/imm32/alloc-id:fake
17248     Single-int-var-in-some-register/imm32/outputs
17249     0x11/imm32/alloc-id:fake
17250     _string_0f_af_multiply/imm32/subx-name
17251     1/imm32/rm32-is-first-inout
17252     3/imm32/r32-is-first-output
17253     0/imm32/no-imm32
17254     0/imm32/no-imm8
17255     0/imm32/no-disp32
17256     0/imm32/output-is-write-only
17257     0x11/imm32/alloc-id:fake
17258     _Primitive-break-if-addr</imm32/next
17259 # - branches
17260 _Primitive-break-if-addr<:  # (payload primitive)
17261     0x11/imm32/alloc-id:fake:payload
17262     0x11/imm32/alloc-id:fake
17263     _string-break-if-addr</imm32/name
17264     0/imm32/no-inouts
17265     0/imm32/no-inouts
17266     0/imm32/no-outputs
17267     0/imm32/no-outputs
17268     0x11/imm32/alloc-id:fake
17269     _string_0f_82_jump_break/imm32/subx-name
17270     0/imm32/no-rm32
17271     0/imm32/no-r32
17272     0/imm32/no-imm32
17273     0/imm32/no-imm8
17274     0/imm32/no-disp32
17275     0/imm32/no-output
17276     0x11/imm32/alloc-id:fake
17277     _Primitive-break-if-addr>=/imm32/next
17278 _Primitive-break-if-addr>=:  # (payload primitive)
17279     0x11/imm32/alloc-id:fake:payload
17280     0x11/imm32/alloc-id:fake
17281     _string-break-if-addr>=/imm32/name
17282     0/imm32/no-inouts
17283     0/imm32/no-inouts
17284     0/imm32/no-outputs
17285     0/imm32/no-outputs
17286     0x11/imm32/alloc-id:fake
17287     _string_0f_83_jump_break/imm32/subx-name
17288     0/imm32/no-rm32
17289     0/imm32/no-r32
17290     0/imm32/no-imm32
17291     0/imm32/no-imm8
17292     0/imm32/no-disp32
17293     0/imm32/no-output
17294     0x11/imm32/alloc-id:fake
17295     _Primitive-break-if-=/imm32/next
17296 _Primitive-break-if-=:  # (payload primitive)
17297     0x11/imm32/alloc-id:fake:payload
17298     0x11/imm32/alloc-id:fake
17299     _string-break-if-=/imm32/name
17300     0/imm32/no-inouts
17301     0/imm32/no-inouts
17302     0/imm32/no-outputs
17303     0/imm32/no-outputs
17304     0x11/imm32/alloc-id:fake
17305     _string_0f_84_jump_break/imm32/subx-name
17306     0/imm32/no-rm32
17307     0/imm32/no-r32
17308     0/imm32/no-imm32
17309     0/imm32/no-imm8
17310     0/imm32/no-disp32
17311     0/imm32/no-output
17312     0x11/imm32/alloc-id:fake
17313     _Primitive-break-if-!=/imm32/next
17314 _Primitive-break-if-!=:  # (payload primitive)
17315     0x11/imm32/alloc-id:fake:payload
17316     0x11/imm32/alloc-id:fake
17317     _string-break-if-!=/imm32/name
17318     0/imm32/no-inouts
17319     0/imm32/no-inouts
17320     0/imm32/no-outputs
17321     0/imm32/no-outputs
17322     0x11/imm32/alloc-id:fake
17323     _string_0f_85_jump_break/imm32/subx-name
17324     0/imm32/no-rm32
17325     0/imm32/no-r32
17326     0/imm32/no-imm32
17327     0/imm32/no-imm8
17328     0/imm32/no-disp32
17329     0/imm32/no-output
17330     0x11/imm32/alloc-id:fake
17331     _Primitive-break-if-addr<=/imm32/next
17332 _Primitive-break-if-addr<=:  # (payload primitive)
17333     0x11/imm32/alloc-id:fake:payload
17334     0x11/imm32/alloc-id:fake
17335     _string-break-if-addr<=/imm32/name
17336     0/imm32/no-inouts
17337     0/imm32/no-inouts
17338     0/imm32/no-outputs
17339     0/imm32/no-outputs
17340     0x11/imm32/alloc-id:fake
17341     _string_0f_86_jump_break/imm32/subx-name
17342     0/imm32/no-rm32
17343     0/imm32/no-r32
17344     0/imm32/no-imm32
17345     0/imm32/no-imm8
17346     0/imm32/no-disp32
17347     0/imm32/no-output
17348     0x11/imm32/alloc-id:fake
17349     _Primitive-break-if-addr>/imm32/next
17350 _Primitive-break-if-addr>:  # (payload primitive)
17351     0x11/imm32/alloc-id:fake:payload
17352     0x11/imm32/alloc-id:fake
17353     _string-break-if-addr>/imm32/name
17354     0/imm32/no-inouts
17355     0/imm32/no-inouts
17356     0/imm32/no-outputs
17357     0/imm32/no-outputs
17358     0x11/imm32/alloc-id:fake
17359     _string_0f_87_jump_break/imm32/subx-name
17360     0/imm32/no-rm32
17361     0/imm32/no-r32
17362     0/imm32/no-imm32
17363     0/imm32/no-imm8
17364     0/imm32/no-disp32
17365     0/imm32/no-output
17366     0x11/imm32/alloc-id:fake
17367     _Primitive-break-if-</imm32/next
17368 _Primitive-break-if-<:  # (payload primitive)
17369     0x11/imm32/alloc-id:fake:payload
17370     0x11/imm32/alloc-id:fake
17371     _string-break-if-</imm32/name
17372     0/imm32/no-inouts
17373     0/imm32/no-inouts
17374     0/imm32/no-outputs
17375     0/imm32/no-outputs
17376     0x11/imm32/alloc-id:fake
17377     _string_0f_8c_jump_break/imm32/subx-name
17378     0/imm32/no-rm32
17379     0/imm32/no-r32
17380     0/imm32/no-imm32
17381     0/imm32/no-imm8
17382     0/imm32/no-disp32
17383     0/imm32/no-output
17384     0x11/imm32/alloc-id:fake
17385     _Primitive-break-if->=/imm32/next
17386 _Primitive-break-if->=:  # (payload primitive)
17387     0x11/imm32/alloc-id:fake:payload
17388     0x11/imm32/alloc-id:fake
17389     _string-break-if->=/imm32/name
17390     0/imm32/no-inouts
17391     0/imm32/no-inouts
17392     0/imm32/no-outputs
17393     0/imm32/no-outputs
17394     0x11/imm32/alloc-id:fake
17395     _string_0f_8d_jump_break/imm32/subx-name
17396     0/imm32/no-rm32
17397     0/imm32/no-r32
17398     0/imm32/no-imm32
17399     0/imm32/no-imm8
17400     0/imm32/no-disp32
17401     0/imm32/no-output
17402     0x11/imm32/alloc-id:fake
17403     _Primitive-break-if-<=/imm32/next
17404 _Primitive-break-if-<=:  # (payload primitive)
17405     0x11/imm32/alloc-id:fake:payload
17406     0x11/imm32/alloc-id:fake
17407     _string-break-if-<=/imm32/name
17408     0/imm32/no-inouts
17409     0/imm32/no-inouts
17410     0/imm32/no-outputs
17411     0/imm32/no-outputs
17412     0x11/imm32/alloc-id:fake
17413     _string_0f_8e_jump_break/imm32/subx-name
17414     0/imm32/no-rm32
17415     0/imm32/no-r32
17416     0/imm32/no-imm32
17417     0/imm32/no-imm8
17418     0/imm32/no-disp32
17419     0/imm32/no-output
17420     0x11/imm32/alloc-id:fake
17421     _Primitive-break-if->/imm32/next
17422 _Primitive-break-if->:  # (payload primitive)
17423     0x11/imm32/alloc-id:fake:payload
17424     0x11/imm32/alloc-id:fake
17425     _string-break-if->/imm32/name
17426     0/imm32/no-inouts
17427     0/imm32/no-inouts
17428     0/imm32/no-outputs
17429     0/imm32/no-outputs
17430     0x11/imm32/alloc-id:fake
17431     _string_0f_8f_jump_break/imm32/subx-name
17432     0/imm32/no-rm32
17433     0/imm32/no-r32
17434     0/imm32/no-imm32
17435     0/imm32/no-imm8
17436     0/imm32/no-disp32
17437     0/imm32/no-output
17438     0x11/imm32/alloc-id:fake
17439     _Primitive-break/imm32/next
17440 _Primitive-break:  # (payload primitive)
17441     0x11/imm32/alloc-id:fake:payload
17442     0x11/imm32/alloc-id:fake
17443     _string-break/imm32/name
17444     0/imm32/no-inouts
17445     0/imm32/no-inouts
17446     0/imm32/no-outputs
17447     0/imm32/no-outputs
17448     0x11/imm32/alloc-id:fake
17449     _string_e9_jump_break/imm32/subx-name
17450     0/imm32/no-rm32
17451     0/imm32/no-r32
17452     0/imm32/no-imm32
17453     0/imm32/no-imm8
17454     0/imm32/no-disp32
17455     0/imm32/no-output
17456     0x11/imm32/alloc-id:fake
17457     _Primitive-loop-if-addr</imm32/next
17458 _Primitive-loop-if-addr<:  # (payload primitive)
17459     0x11/imm32/alloc-id:fake:payload
17460     0x11/imm32/alloc-id:fake
17461     _string-loop-if-addr</imm32/name
17462     0/imm32/no-inouts
17463     0/imm32/no-inouts
17464     0/imm32/no-outputs
17465     0/imm32/no-outputs
17466     0x11/imm32/alloc-id:fake
17467     _string_0f_82_jump_loop/imm32/subx-name
17468     0/imm32/no-rm32
17469     0/imm32/no-r32
17470     0/imm32/no-imm32
17471     0/imm32/no-imm8
17472     0/imm32/no-disp32
17473     0/imm32/no-output
17474     0x11/imm32/alloc-id:fake
17475     _Primitive-loop-if-addr>=/imm32/next
17476 _Primitive-loop-if-addr>=:  # (payload primitive)
17477     0x11/imm32/alloc-id:fake:payload
17478     0x11/imm32/alloc-id:fake
17479     _string-loop-if-addr>=/imm32/name
17480     0/imm32/no-inouts
17481     0/imm32/no-inouts
17482     0/imm32/no-outputs
17483     0/imm32/no-outputs
17484     0x11/imm32/alloc-id:fake
17485     _string_0f_83_jump_loop/imm32/subx-name
17486     0/imm32/no-rm32
17487     0/imm32/no-r32
17488     0/imm32/no-imm32
17489     0/imm32/no-imm8
17490     0/imm32/no-disp32
17491     0/imm32/no-output
17492     0x11/imm32/alloc-id:fake
17493     _Primitive-loop-if-=/imm32/next
17494 _Primitive-loop-if-=:  # (payload primitive)
17495     0x11/imm32/alloc-id:fake:payload
17496     0x11/imm32/alloc-id:fake
17497     _string-loop-if-=/imm32/name
17498     0/imm32/no-inouts
17499     0/imm32/no-inouts
17500     0/imm32/no-outputs
17501     0/imm32/no-outputs
17502     0x11/imm32/alloc-id:fake
17503     _string_0f_84_jump_loop/imm32/subx-name
17504     0/imm32/no-rm32
17505     0/imm32/no-r32
17506     0/imm32/no-imm32
17507     0/imm32/no-imm8
17508     0/imm32/no-disp32
17509     0/imm32/no-output
17510     0x11/imm32/alloc-id:fake
17511     _Primitive-loop-if-!=/imm32/next
17512 _Primitive-loop-if-!=:  # (payload primitive)
17513     0x11/imm32/alloc-id:fake:payload
17514     0x11/imm32/alloc-id:fake
17515     _string-loop-if-!=/imm32/name
17516     0/imm32/no-inouts
17517     0/imm32/no-inouts
17518     0/imm32/no-outputs
17519     0/imm32/no-outputs
17520     0x11/imm32/alloc-id:fake
17521     _string_0f_85_jump_loop/imm32/subx-name
17522     0/imm32/no-rm32
17523     0/imm32/no-r32
17524     0/imm32/no-imm32
17525     0/imm32/no-imm8
17526     0/imm32/no-disp32
17527     0/imm32/no-output
17528     0x11/imm32/alloc-id:fake
17529     _Primitive-loop-if-addr<=/imm32/next
17530 _Primitive-loop-if-addr<=:  # (payload primitive)
17531     0x11/imm32/alloc-id:fake:payload
17532     0x11/imm32/alloc-id:fake
17533     _string-loop-if-addr<=/imm32/name
17534     0/imm32/no-inouts
17535     0/imm32/no-inouts
17536     0/imm32/no-outputs
17537     0/imm32/no-outputs
17538     0x11/imm32/alloc-id:fake
17539     _string_0f_86_jump_loop/imm32/subx-name
17540     0/imm32/no-rm32
17541     0/imm32/no-r32
17542     0/imm32/no-imm32
17543     0/imm32/no-imm8
17544     0/imm32/no-disp32
17545     0/imm32/no-output
17546     0x11/imm32/alloc-id:fake
17547     _Primitive-loop-if-addr>/imm32/next
17548 _Primitive-loop-if-addr>:  # (payload primitive)
17549     0x11/imm32/alloc-id:fake:payload
17550     0x11/imm32/alloc-id:fake
17551     _string-loop-if-addr>/imm32/name
17552     0/imm32/no-inouts
17553     0/imm32/no-inouts
17554     0/imm32/no-outputs
17555     0/imm32/no-outputs
17556     0x11/imm32/alloc-id:fake
17557     _string_0f_87_jump_loop/imm32/subx-name
17558     0/imm32/no-rm32
17559     0/imm32/no-r32
17560     0/imm32/no-imm32
17561     0/imm32/no-imm8
17562     0/imm32/no-disp32
17563     0/imm32/no-output
17564     0x11/imm32/alloc-id:fake
17565     _Primitive-loop-if-</imm32/next
17566 _Primitive-loop-if-<:  # (payload primitive)
17567     0x11/imm32/alloc-id:fake:payload
17568     0x11/imm32/alloc-id:fake
17569     _string-loop-if-</imm32/name
17570     0/imm32/no-inouts
17571     0/imm32/no-inouts
17572     0/imm32/no-outputs
17573     0/imm32/no-outputs
17574     0x11/imm32/alloc-id:fake
17575     _string_0f_8c_jump_loop/imm32/subx-name
17576     0/imm32/no-rm32
17577     0/imm32/no-r32
17578     0/imm32/no-imm32
17579     0/imm32/no-imm8
17580     0/imm32/no-disp32
17581     0/imm32/no-output
17582     0x11/imm32/alloc-id:fake
17583     _Primitive-loop-if->=/imm32/next
17584 _Primitive-loop-if->=:  # (payload primitive)
17585     0x11/imm32/alloc-id:fake:payload
17586     0x11/imm32/alloc-id:fake
17587     _string-loop-if->=/imm32/name
17588     0/imm32/no-inouts
17589     0/imm32/no-inouts
17590     0/imm32/no-outputs
17591     0/imm32/no-outputs
17592     0x11/imm32/alloc-id:fake
17593     _string_0f_8d_jump_loop/imm32/subx-name
17594     0/imm32/no-rm32
17595     0/imm32/no-r32
17596     0/imm32/no-imm32
17597     0/imm32/no-imm8
17598     0/imm32/no-disp32
17599     0/imm32/no-output
17600     0x11/imm32/alloc-id:fake
17601     _Primitive-loop-if-<=/imm32/next
17602 _Primitive-loop-if-<=:  # (payload primitive)
17603     0x11/imm32/alloc-id:fake:payload
17604     0x11/imm32/alloc-id:fake
17605     _string-loop-if-<=/imm32/name
17606     0/imm32/no-inouts
17607     0/imm32/no-inouts
17608     0/imm32/no-outputs
17609     0/imm32/no-outputs
17610     0x11/imm32/alloc-id:fake
17611     _string_0f_8e_jump_loop/imm32/subx-name
17612     0/imm32/no-rm32
17613     0/imm32/no-r32
17614     0/imm32/no-imm32
17615     0/imm32/no-imm8
17616     0/imm32/no-disp32
17617     0/imm32/no-output
17618     0x11/imm32/alloc-id:fake
17619     _Primitive-loop-if->/imm32/next
17620 _Primitive-loop-if->:  # (payload primitive)
17621     0x11/imm32/alloc-id:fake:payload
17622     0x11/imm32/alloc-id:fake
17623     _string-loop-if->/imm32/name
17624     0/imm32/no-inouts
17625     0/imm32/no-inouts
17626     0/imm32/no-outputs
17627     0/imm32/no-outputs
17628     0x11/imm32/alloc-id:fake
17629     _string_0f_8f_jump_loop/imm32/subx-name
17630     0/imm32/no-rm32
17631     0/imm32/no-r32
17632     0/imm32/no-imm32
17633     0/imm32/no-imm8
17634     0/imm32/no-disp32
17635     0/imm32/no-output
17636     0x11/imm32/alloc-id:fake
17637     _Primitive-loop/imm32/next  # we probably don't need an unconditional break
17638 _Primitive-loop:  # (payload primitive)
17639     0x11/imm32/alloc-id:fake:payload
17640     0x11/imm32/alloc-id:fake
17641     _string-loop/imm32/name
17642     0/imm32/no-inouts
17643     0/imm32/no-inouts
17644     0/imm32/no-outputs
17645     0/imm32/no-outputs
17646     0x11/imm32/alloc-id:fake
17647     _string_e9_jump_loop/imm32/subx-name
17648     0/imm32/no-rm32
17649     0/imm32/no-r32
17650     0/imm32/no-imm32
17651     0/imm32/no-imm8
17652     0/imm32/no-disp32
17653     0/imm32/no-output
17654     0x11/imm32/alloc-id:fake
17655     _Primitive-break-if-addr<-named/imm32/next
17656 # - branches to named blocks
17657 _Primitive-break-if-addr<-named:  # (payload primitive)
17658     0x11/imm32/alloc-id:fake:payload
17659     0x11/imm32/alloc-id:fake
17660     _string-break-if-addr</imm32/name
17661     0x11/imm32/alloc-id:fake
17662     Single-lit-var/imm32/inouts
17663     0/imm32/no-outputs
17664     0/imm32/no-outputs
17665     0x11/imm32/alloc-id:fake
17666     _string_0f_82_jump_label/imm32/subx-name
17667     0/imm32/no-rm32
17668     0/imm32/no-r32
17669     0/imm32/no-imm32
17670     0/imm32/no-imm8
17671     1/imm32/disp32-is-first-inout
17672     0/imm32/no-output
17673     0x11/imm32/alloc-id:fake
17674     _Primitive-break-if-addr>=-named/imm32/next
17675 _Primitive-break-if-addr>=-named:  # (payload primitive)
17676     0x11/imm32/alloc-id:fake:payload
17677     0x11/imm32/alloc-id:fake
17678     _string-break-if-addr>=/imm32/name
17679     0x11/imm32/alloc-id:fake
17680     Single-lit-var/imm32/inouts
17681     0/imm32/no-outputs
17682     0/imm32/no-outputs
17683     0x11/imm32/alloc-id:fake
17684     _string_0f_83_jump_label/imm32/subx-name
17685     0/imm32/no-rm32
17686     0/imm32/no-r32
17687     0/imm32/no-imm32
17688     0/imm32/no-imm8
17689     1/imm32/disp32-is-first-inout
17690     0/imm32/no-output
17691     0x11/imm32/alloc-id:fake
17692     _Primitive-break-if-=-named/imm32/next
17693 _Primitive-break-if-=-named:  # (payload primitive)
17694     0x11/imm32/alloc-id:fake:payload
17695     0x11/imm32/alloc-id:fake
17696     _string-break-if-=/imm32/name
17697     0x11/imm32/alloc-id:fake
17698     Single-lit-var/imm32/inouts
17699     0/imm32/no-outputs
17700     0/imm32/no-outputs
17701     0x11/imm32/alloc-id:fake
17702     _string_0f_84_jump_label/imm32/subx-name
17703     0/imm32/no-rm32
17704     0/imm32/no-r32
17705     0/imm32/no-imm32
17706     0/imm32/no-imm8
17707     1/imm32/disp32-is-first-inout
17708     0/imm32/no-output
17709     0x11/imm32/alloc-id:fake
17710     _Primitive-break-if-!=-named/imm32/next
17711 _Primitive-break-if-!=-named:  # (payload primitive)
17712     0x11/imm32/alloc-id:fake:payload
17713     0x11/imm32/alloc-id:fake
17714     _string-break-if-!=/imm32/name
17715     0x11/imm32/alloc-id:fake
17716     Single-lit-var/imm32/inouts
17717     0/imm32/no-outputs
17718     0/imm32/no-outputs
17719     0x11/imm32/alloc-id:fake
17720     _string_0f_85_jump_label/imm32/subx-name
17721     0/imm32/no-rm32
17722     0/imm32/no-r32
17723     0/imm32/no-imm32
17724     0/imm32/no-imm8
17725     1/imm32/disp32-is-first-inout
17726     0/imm32/no-output
17727     0x11/imm32/alloc-id:fake
17728     _Primitive-break-if-addr<=-named/imm32/next
17729 _Primitive-break-if-addr<=-named:  # (payload primitive)
17730     0x11/imm32/alloc-id:fake:payload
17731     0x11/imm32/alloc-id:fake
17732     _string-break-if-addr<=/imm32/name
17733     0x11/imm32/alloc-id:fake
17734     Single-lit-var/imm32/inouts
17735     0/imm32/no-outputs
17736     0/imm32/no-outputs
17737     0x11/imm32/alloc-id:fake
17738     _string_0f_86_jump_label/imm32/subx-name
17739     0/imm32/no-rm32
17740     0/imm32/no-r32
17741     0/imm32/no-imm32
17742     0/imm32/no-imm8
17743     1/imm32/disp32-is-first-inout
17744     0/imm32/no-output
17745     0x11/imm32/alloc-id:fake
17746     _Primitive-break-if-addr>-named/imm32/next
17747 _Primitive-break-if-addr>-named:  # (payload primitive)
17748     0x11/imm32/alloc-id:fake:payload
17749     0x11/imm32/alloc-id:fake
17750     _string-break-if-addr>/imm32/name
17751     0x11/imm32/alloc-id:fake
17752     Single-lit-var/imm32/inouts
17753     0/imm32/no-outputs
17754     0/imm32/no-outputs
17755     0x11/imm32/alloc-id:fake
17756     _string_0f_87_jump_label/imm32/subx-name
17757     0/imm32/no-rm32
17758     0/imm32/no-r32
17759     0/imm32/no-imm32
17760     0/imm32/no-imm8
17761     1/imm32/disp32-is-first-inout
17762     0/imm32/no-output
17763     0x11/imm32/alloc-id:fake
17764     _Primitive-break-if-<-named/imm32/next
17765 _Primitive-break-if-<-named:  # (payload primitive)
17766     0x11/imm32/alloc-id:fake:payload
17767     0x11/imm32/alloc-id:fake
17768     _string-break-if-</imm32/name
17769     0x11/imm32/alloc-id:fake
17770     Single-lit-var/imm32/inouts
17771     0/imm32/no-outputs
17772     0/imm32/no-outputs
17773     0x11/imm32/alloc-id:fake
17774     _string_0f_8c_jump_label/imm32/subx-name
17775     0/imm32/no-rm32
17776     0/imm32/no-r32
17777     0/imm32/no-imm32
17778     0/imm32/no-imm8
17779     1/imm32/disp32-is-first-inout
17780     0/imm32/no-output
17781     0x11/imm32/alloc-id:fake
17782     _Primitive-break-if->=-named/imm32/next
17783 _Primitive-break-if->=-named:  # (payload primitive)
17784     0x11/imm32/alloc-id:fake:payload
17785     0x11/imm32/alloc-id:fake
17786     _string-break-if->=/imm32/name
17787     0x11/imm32/alloc-id:fake
17788     Single-lit-var/imm32/inouts
17789     0/imm32/no-outputs
17790     0/imm32/no-outputs
17791     0x11/imm32/alloc-id:fake
17792     _string_0f_8d_jump_label/imm32/subx-name
17793     0/imm32/no-rm32
17794     0/imm32/no-r32
17795     0/imm32/no-imm32
17796     0/imm32/no-imm8
17797     1/imm32/disp32-is-first-inout
17798     0/imm32/no-output
17799     0x11/imm32/alloc-id:fake
17800     _Primitive-break-if-<=-named/imm32/next
17801 _Primitive-break-if-<=-named:  # (payload primitive)
17802     0x11/imm32/alloc-id:fake:payload
17803     0x11/imm32/alloc-id:fake
17804     _string-break-if-<=/imm32/name
17805     0x11/imm32/alloc-id:fake
17806     Single-lit-var/imm32/inouts
17807     0/imm32/no-outputs
17808     0/imm32/no-outputs
17809     0x11/imm32/alloc-id:fake
17810     _string_0f_8e_jump_label/imm32/subx-name
17811     0/imm32/no-rm32
17812     0/imm32/no-r32
17813     0/imm32/no-imm32
17814     0/imm32/no-imm8
17815     1/imm32/disp32-is-first-inout
17816     0/imm32/no-output
17817     0x11/imm32/alloc-id:fake
17818     _Primitive-break-if->-named/imm32/next
17819 _Primitive-break-if->-named:  # (payload primitive)
17820     0x11/imm32/alloc-id:fake:payload
17821     0x11/imm32/alloc-id:fake
17822     _string-break-if->/imm32/name
17823     0x11/imm32/alloc-id:fake
17824     Single-lit-var/imm32/inouts
17825     0/imm32/no-outputs
17826     0/imm32/no-outputs
17827     0x11/imm32/alloc-id:fake
17828     _string_0f_8f_jump_label/imm32/subx-name
17829     0/imm32/no-rm32
17830     0/imm32/no-r32
17831     0/imm32/no-imm32
17832     0/imm32/no-imm8
17833     1/imm32/disp32-is-first-inout
17834     0/imm32/no-output
17835     0x11/imm32/alloc-id:fake
17836     _Primitive-break-named/imm32/next
17837 _Primitive-break-named:  # (payload primitive)
17838     0x11/imm32/alloc-id:fake:payload
17839     0x11/imm32/alloc-id:fake
17840     _string-break/imm32/name
17841     0x11/imm32/alloc-id:fake
17842     Single-lit-var/imm32/inouts
17843     0/imm32/no-outputs
17844     0/imm32/no-outputs
17845     0x11/imm32/alloc-id:fake
17846     _string_e9_jump_label/imm32/subx-name
17847     0/imm32/no-rm32
17848     0/imm32/no-r32
17849     0/imm32/no-imm32
17850     0/imm32/no-imm8
17851     1/imm32/disp32-is-first-inout
17852     0/imm32/no-output
17853     0x11/imm32/alloc-id:fake
17854     _Primitive-loop-if-addr<-named/imm32/next
17855 _Primitive-loop-if-addr<-named:  # (payload primitive)
17856     0x11/imm32/alloc-id:fake:payload
17857     0x11/imm32/alloc-id:fake
17858     _string-loop-if-addr</imm32/name
17859     0x11/imm32/alloc-id:fake
17860     Single-lit-var/imm32/inouts
17861     0/imm32/no-outputs
17862     0/imm32/no-outputs
17863     0x11/imm32/alloc-id:fake
17864     _string_0f_82_jump_label/imm32/subx-name
17865     0/imm32/no-rm32
17866     0/imm32/no-r32
17867     0/imm32/no-imm32
17868     0/imm32/no-imm8
17869     1/imm32/disp32-is-first-inout
17870     0/imm32/no-output
17871     0x11/imm32/alloc-id:fake
17872     _Primitive-loop-if-addr>=-named/imm32/next
17873 _Primitive-loop-if-addr>=-named:  # (payload primitive)
17874     0x11/imm32/alloc-id:fake:payload
17875     0x11/imm32/alloc-id:fake
17876     _string-loop-if-addr>=/imm32/name
17877     0x11/imm32/alloc-id:fake
17878     Single-lit-var/imm32/inouts
17879     0/imm32/no-outputs
17880     0/imm32/no-outputs
17881     0x11/imm32/alloc-id:fake
17882     _string_0f_83_jump_label/imm32/subx-name
17883     0/imm32/no-rm32
17884     0/imm32/no-r32
17885     0/imm32/no-imm32
17886     0/imm32/no-imm8
17887     1/imm32/disp32-is-first-inout
17888     0/imm32/no-output
17889     0x11/imm32/alloc-id:fake
17890     _Primitive-loop-if-=-named/imm32/next
17891 _Primitive-loop-if-=-named:  # (payload primitive)
17892     0x11/imm32/alloc-id:fake:payload
17893     0x11/imm32/alloc-id:fake
17894     _string-loop-if-=/imm32/name
17895     0x11/imm32/alloc-id:fake
17896     Single-lit-var/imm32/inouts
17897     0/imm32/no-outputs
17898     0/imm32/no-outputs
17899     0x11/imm32/alloc-id:fake
17900     _string_0f_84_jump_label/imm32/subx-name
17901     0/imm32/no-rm32
17902     0/imm32/no-r32
17903     0/imm32/no-imm32
17904     0/imm32/no-imm8
17905     1/imm32/disp32-is-first-inout
17906     0/imm32/no-output
17907     0x11/imm32/alloc-id:fake
17908     _Primitive-loop-if-!=-named/imm32/next
17909 _Primitive-loop-if-!=-named:  # (payload primitive)
17910     0x11/imm32/alloc-id:fake:payload
17911     0x11/imm32/alloc-id:fake
17912     _string-loop-if-!=/imm32/name
17913     0x11/imm32/alloc-id:fake
17914     Single-lit-var/imm32/inouts
17915     0/imm32/no-outputs
17916     0/imm32/no-outputs
17917     0x11/imm32/alloc-id:fake
17918     _string_0f_85_jump_label/imm32/subx-name
17919     0/imm32/no-rm32
17920     0/imm32/no-r32
17921     0/imm32/no-imm32
17922     0/imm32/no-imm8
17923     1/imm32/disp32-is-first-inout
17924     0/imm32/no-output
17925     0x11/imm32/alloc-id:fake
17926     _Primitive-loop-if-addr<=-named/imm32/next
17927 _Primitive-loop-if-addr<=-named:  # (payload primitive)
17928     0x11/imm32/alloc-id:fake:payload
17929     0x11/imm32/alloc-id:fake
17930     _string-loop-if-addr<=/imm32/name
17931     0x11/imm32/alloc-id:fake
17932     Single-lit-var/imm32/inouts
17933     0/imm32/no-outputs
17934     0/imm32/no-outputs
17935     0x11/imm32/alloc-id:fake
17936     _string_0f_86_jump_label/imm32/subx-name
17937     0/imm32/no-rm32
17938     0/imm32/no-r32
17939     0/imm32/no-imm32
17940     0/imm32/no-imm8
17941     1/imm32/disp32-is-first-inout
17942     0/imm32/no-output
17943     0x11/imm32/alloc-id:fake
17944     _Primitive-loop-if-addr>-named/imm32/next
17945 _Primitive-loop-if-addr>-named:  # (payload primitive)
17946     0x11/imm32/alloc-id:fake:payload
17947     0x11/imm32/alloc-id:fake
17948     _string-loop-if-addr>/imm32/name
17949     0x11/imm32/alloc-id:fake
17950     Single-lit-var/imm32/inouts
17951     0/imm32/no-outputs
17952     0/imm32/no-outputs
17953     0x11/imm32/alloc-id:fake
17954     _string_0f_87_jump_label/imm32/subx-name
17955     0/imm32/no-rm32
17956     0/imm32/no-r32
17957     0/imm32/no-imm32
17958     0/imm32/no-imm8
17959     1/imm32/disp32-is-first-inout
17960     0/imm32/no-output
17961     0x11/imm32/alloc-id:fake
17962     _Primitive-loop-if-<-named/imm32/next
17963 _Primitive-loop-if-<-named:  # (payload primitive)
17964     0x11/imm32/alloc-id:fake:payload
17965     0x11/imm32/alloc-id:fake
17966     _string-loop-if-</imm32/name
17967     0x11/imm32/alloc-id:fake
17968     Single-lit-var/imm32/inouts
17969     0/imm32/no-outputs
17970     0/imm32/no-outputs
17971     0x11/imm32/alloc-id:fake
17972     _string_0f_8c_jump_label/imm32/subx-name
17973     0/imm32/no-rm32
17974     0/imm32/no-r32
17975     0/imm32/no-imm32
17976     0/imm32/no-imm8
17977     1/imm32/disp32-is-first-inout
17978     0/imm32/no-output
17979     0x11/imm32/alloc-id:fake
17980     _Primitive-loop-if->=-named/imm32/next
17981 _Primitive-loop-if->=-named:  # (payload primitive)
17982     0x11/imm32/alloc-id:fake:payload
17983     0x11/imm32/alloc-id:fake
17984     _string-loop-if->=/imm32/name
17985     0x11/imm32/alloc-id:fake
17986     Single-lit-var/imm32/inouts
17987     0/imm32/no-outputs
17988     0/imm32/no-outputs
17989     0x11/imm32/alloc-id:fake
17990     _string_0f_8d_jump_label/imm32/subx-name
17991     0/imm32/no-rm32
17992     0/imm32/no-r32
17993     0/imm32/no-imm32
17994     0/imm32/no-imm8
17995     1/imm32/disp32-is-first-inout
17996     0/imm32/no-output
17997     0x11/imm32/alloc-id:fake
17998     _Primitive-loop-if-<=-named/imm32/next
17999 _Primitive-loop-if-<=-named:  # (payload primitive)
18000     0x11/imm32/alloc-id:fake:payload
18001     0x11/imm32/alloc-id:fake
18002     _string-loop-if-<=/imm32/name
18003     0x11/imm32/alloc-id:fake
18004     Single-lit-var/imm32/inouts
18005     0/imm32/no-outputs
18006     0/imm32/no-outputs
18007     0x11/imm32/alloc-id:fake
18008     _string_0f_8e_jump_label/imm32/subx-name
18009     0/imm32/no-rm32
18010     0/imm32/no-r32
18011     0/imm32/no-imm32
18012     0/imm32/no-imm8
18013     1/imm32/disp32-is-first-inout
18014     0/imm32/no-output
18015     0x11/imm32/alloc-id:fake
18016     _Primitive-loop-if->-named/imm32/next
18017 _Primitive-loop-if->-named:  # (payload primitive)
18018     0x11/imm32/alloc-id:fake:payload
18019     0x11/imm32/alloc-id:fake
18020     _string-loop-if->/imm32/name
18021     0x11/imm32/alloc-id:fake
18022     Single-lit-var/imm32/inouts
18023     0/imm32/no-outputs
18024     0/imm32/no-outputs
18025     0x11/imm32/alloc-id:fake
18026     _string_0f_8f_jump_label/imm32/subx-name
18027     0/imm32/no-rm32
18028     0/imm32/no-r32
18029     0/imm32/no-imm32
18030     0/imm32/no-imm8
18031     1/imm32/disp32-is-first-inout
18032     0/imm32/no-output
18033     0x11/imm32/alloc-id:fake
18034     _Primitive-loop-named/imm32/next  # we probably don't need an unconditional break
18035 _Primitive-loop-named:  # (payload primitive)
18036     0x11/imm32/alloc-id:fake:payload
18037     0x11/imm32/alloc-id:fake
18038     _string-loop/imm32/name
18039     0x11/imm32/alloc-id:fake
18040     Single-lit-var/imm32/inouts
18041     0/imm32/no-outputs
18042     0/imm32/no-outputs
18043     0x11/imm32/alloc-id:fake
18044     _string_e9_jump_label/imm32/subx-name
18045     0/imm32/no-rm32
18046     0/imm32/no-r32
18047     0/imm32/no-imm32
18048     0/imm32/no-imm8
18049     1/imm32/disp32-is-first-inout
18050     0/imm32/no-output
18051     0/imm32/next
18052     0/imm32/next
18053 
18054 # string literals for Mu instructions
18055 _string-add:  # (payload array byte)
18056     0x11/imm32/alloc-id:fake:payload
18057     # "add"
18058     0x3/imm32/size
18059     0x61/a 0x64/d 0x64/d
18060 _string-address:  # (payload array byte)
18061     0x11/imm32/alloc-id:fake:payload
18062     # "address"
18063     0x7/imm32/size
18064     0x61/a 0x64/d 0x64/d 0x72/r 0x65/e 0x73/s 0x73/s
18065 _string-add-to:  # (payload array byte)
18066     0x11/imm32/alloc-id:fake:payload
18067     # "add-to"
18068     0x6/imm32/size
18069     0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
18070 _string-and:  # (payload array byte)
18071     0x11/imm32/alloc-id:fake:payload
18072     # "and"
18073     0x3/imm32/size
18074     0x61/a 0x6e/n 0x64/d
18075 _string-and-with:  # (payload array byte)
18076     0x11/imm32/alloc-id:fake:payload
18077     # "and-with"
18078     0x8/imm32/size
18079     0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
18080 _string-break:  # (payload array byte)
18081     0x11/imm32/alloc-id:fake:payload
18082     # "break"
18083     0x5/imm32/size
18084     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k
18085 _string-break-if-<:  # (payload array byte)
18086     0x11/imm32/alloc-id:fake:payload
18087     # "break-if-<"
18088     0xa/imm32/size
18089     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
18090 _string-break-if-<=:  # (payload array byte)
18091     0x11/imm32/alloc-id:fake:payload
18092     # "break-if-<="
18093     0xb/imm32/size
18094     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
18095 _string-break-if-=:  # (payload array byte)
18096     0x11/imm32/alloc-id:fake:payload
18097     # "break-if-="
18098     0xa/imm32/size
18099     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
18100 _string-break-if->:  # (payload array byte)
18101     0x11/imm32/alloc-id:fake:payload
18102     # "break-if->"
18103     0xa/imm32/size
18104     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
18105 _string-break-if->=:  # (payload array byte)
18106     0x11/imm32/alloc-id:fake:payload
18107     # "break-if->="
18108     0xb/imm32/size
18109     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
18110 _string-break-if-!=:  # (payload array byte)
18111     0x11/imm32/alloc-id:fake:payload
18112     # "break-if-!="
18113     0xb/imm32/size
18114     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
18115 _string-break-if-addr<:  # (payload array byte)
18116     0x11/imm32/alloc-id:fake:payload
18117     # "break-if-addr<"
18118     0xe/imm32/size
18119     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/<
18120 _string-break-if-addr<=:  # (payload array byte)
18121     0x11/imm32/alloc-id:fake:payload
18122     # "break-if-addr<="
18123     0xf/imm32/size
18124     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/=
18125 _string-break-if-addr>:  # (payload array byte)
18126     0x11/imm32/alloc-id:fake:payload
18127     # "break-if-addr>"
18128     0xe/imm32/size
18129     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/>
18130 _string-break-if-addr>=:  # (payload array byte)
18131     0x11/imm32/alloc-id:fake:payload
18132     # "break-if-addr>="
18133     0xf/imm32/size
18134     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/=
18135 _string-compare:  # (payload array byte)
18136     0x11/imm32/alloc-id:fake:payload
18137     # "compare"
18138     0x7/imm32/size
18139     0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e
18140 _string-copy:  # (payload array byte)
18141     0x11/imm32/alloc-id:fake:payload
18142     # "copy"
18143     0x4/imm32/size
18144     0x63/c 0x6f/o 0x70/p 0x79/y
18145 _string-copy-to:  # (payload array byte)
18146     0x11/imm32/alloc-id:fake:payload
18147     # "copy-to"
18148     0x7/imm32/size
18149     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o
18150 _string-copy-byte:
18151     0x11/imm32/alloc-id:fake:payload
18152     # "copy-byte"
18153     0x9/imm32/size
18154     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e
18155 _string-copy-byte-to:
18156     0x11/imm32/alloc-id:fake:payload
18157     # "copy-byte-to"
18158     0xc/imm32/size
18159     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x74/t 0x6f/o
18160 _string-decrement:  # (payload array byte)
18161     0x11/imm32/alloc-id:fake:payload
18162     # "decrement"
18163     0x9/imm32/size
18164     0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
18165 _string-increment:  # (payload array byte)
18166     0x11/imm32/alloc-id:fake:payload
18167     # "increment"
18168     0x9/imm32/size
18169     0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
18170 _string-loop:  # (payload array byte)
18171     0x11/imm32/alloc-id:fake:payload
18172     # "loop"
18173     0x4/imm32/size
18174     0x6c/l 0x6f/o 0x6f/o 0x70/p
18175 _string-loop-if-<:  # (payload array byte)
18176     0x11/imm32/alloc-id:fake:payload
18177     # "loop-if-<"
18178     0x9/imm32/size
18179     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
18180 _string-loop-if-<=:  # (payload array byte)
18181     0x11/imm32/alloc-id:fake:payload
18182     # "loop-if-<="
18183     0xa/imm32/size
18184     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
18185 _string-loop-if-=:  # (payload array byte)
18186     0x11/imm32/alloc-id:fake:payload
18187     # "loop-if-="
18188     0x9/imm32/size
18189     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
18190 _string-loop-if->:  # (payload array byte)
18191     0x11/imm32/alloc-id:fake:payload
18192     # "loop-if->"
18193     0x9/imm32/size
18194     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
18195 _string-loop-if->=:  # (payload array byte)
18196     0x11/imm32/alloc-id:fake:payload
18197     # "loop-if->="
18198     0xa/imm32/size
18199     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
18200 _string-loop-if-!=:  # (payload array byte)
18201     0x11/imm32/alloc-id:fake:payload
18202     # "loop-if-!="
18203     0xa/imm32/size
18204     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
18205 _string-loop-if-addr<:  # (payload array byte)
18206     0x11/imm32/alloc-id:fake:payload
18207     # "loop-if-addr<"
18208     0xd/imm32/size
18209     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/<
18210 _string-loop-if-addr<=:  # (payload array byte)
18211     0x11/imm32/alloc-id:fake:payload
18212     # "loop-if-addr<="
18213     0xe/imm32/size
18214     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/=
18215 _string-loop-if-addr>:  # (payload array byte)
18216     0x11/imm32/alloc-id:fake:payload
18217     # "loop-if-addr>"
18218     0xd/imm32/size
18219     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/>
18220 _string-loop-if-addr>=:  # (payload array byte)
18221     0x11/imm32/alloc-id:fake:payload
18222     # "loop-if-addr>="
18223     0xe/imm32/size
18224     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/=
18225 _string-multiply:  # (payload array byte)
18226     0x11/imm32/alloc-id:fake:payload
18227     # "multiply"
18228     0x8/imm32/size
18229     0x6d/m 0x75/u 0x6c/l 0x74/t 0x69/i 0x70/p 0x6c/l 0x79/y
18230 _string-or:  # (payload array byte)
18231     0x11/imm32/alloc-id:fake:payload
18232     # "or"
18233     0x2/imm32/size
18234     0x6f/o 0x72/r
18235 _string-or-with:  # (payload array byte)
18236     0x11/imm32/alloc-id:fake:payload
18237     # "or-with"
18238     0x7/imm32/size
18239     0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
18240 _string-subtract:  # (payload array byte)
18241     0x11/imm32/alloc-id:fake:payload
18242     # "subtract"
18243     0x8/imm32/size
18244     0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
18245 _string-subtract-from:  # (payload array byte)
18246     0x11/imm32/alloc-id:fake:payload
18247     # "subtract-from"
18248     0xd/imm32/size
18249     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
18250 _string-xor:  # (payload array byte)
18251     0x11/imm32/alloc-id:fake:payload
18252     # "xor"
18253     0x3/imm32/size
18254     0x78/x 0x6f/o 0x72/r
18255 _string-xor-with:  # (payload array byte)
18256     0x11/imm32/alloc-id:fake:payload
18257     # "xor-with"
18258     0x8/imm32/size
18259     0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
18260 _string-shift-left:  # (payload array byte)
18261     0x11/imm32/alloc-id:fake:payload
18262     # "shift-left"
18263     0xa/imm32/size
18264     0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x2d/dash 0x6c/l 0x65/e 0x66/f 0x74/t
18265 _string-shift-right:  # (payload array byte)
18266     0x11/imm32/alloc-id:fake:payload
18267     # "shift-right"
18268     0xb/imm32/size
18269     0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x2d/dash 0x72/r 0x69/i 0x67/g 0x68/h 0x74/t
18270 _string-shift-right-signed:  # (payload array byte)
18271     0x11/imm32/alloc-id:fake:payload
18272     # "shift-right-signed"
18273     0x12/imm32/size
18274     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
18275 
18276 # string literals for SubX instructions
18277 _string_01_add_to:  # (payload array byte)
18278     0x11/imm32/alloc-id:fake:payload
18279     # "01/add-to"
18280     0x9/imm32/size
18281     0x30/0 0x31/1 0x2f/slash 0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
18282 _string_03_add:  # (payload array byte)
18283     0x11/imm32/alloc-id:fake:payload
18284     # "03/add"
18285     0x6/imm32/size
18286     0x30/0 0x33/3 0x2f/slash 0x61/a 0x64/d 0x64/d
18287 _string_05_add_to_eax:  # (payload array byte)
18288     0x11/imm32/alloc-id:fake:payload
18289     # "05/add-to-eax"
18290     0xd/imm32/size
18291     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
18292 _string_09_or_with:  # (payload array byte)
18293     0x11/imm32/alloc-id:fake:payload
18294     # "09/or-with"
18295     0xa/imm32/size
18296     0x30/0 0x39/9 0x2f/slash 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
18297 _string_0b_or:  # (payload array byte)
18298     0x11/imm32/alloc-id:fake:payload
18299     # "0b/or"
18300     0x5/imm32/size
18301     0x30/0 0x62/b 0x2f/slash 0x6f/o 0x72/r
18302 _string_0d_or_with_eax:  # (payload array byte)
18303     0x11/imm32/alloc-id:fake:payload
18304     # "0d/or-with-eax"
18305     0xe/imm32/size
18306     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
18307 _string_0f_82_jump_label:  # (payload array byte)
18308     0x11/imm32/alloc-id:fake:payload
18309     # "0f 82/jump-if-addr<"
18310     0x13/imm32/size
18311     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/<
18312 _string_0f_82_jump_break:  # (payload array byte)
18313     0x11/imm32/alloc-id:fake:payload
18314     # "0f 82/jump-if-addr< break/disp32"
18315     0x20/imm32/size
18316     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
18317 _string_0f_82_jump_loop:  # (payload array byte)
18318     0x11/imm32/alloc-id:fake:payload
18319     # "0f 82/jump-if-addr< loop/disp32"
18320     0x1f/imm32/size
18321     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
18322 _string_0f_83_jump_label:  # (payload array byte)
18323     0x11/imm32/alloc-id:fake:payload
18324     # "0f 83/jump-if-addr>="
18325     0x14/imm32/size
18326     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/=
18327 _string_0f_83_jump_break:  # (payload array byte)
18328     0x11/imm32/alloc-id:fake:payload
18329     # "0f 83/jump-if-addr>= break/disp32"
18330     0x21/imm32/size
18331     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
18332 _string_0f_83_jump_loop:  # (payload array byte)
18333     0x11/imm32/alloc-id:fake:payload
18334     # "0f 83/jump-if-addr>= loop/disp32"
18335     0x20/imm32/size
18336     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
18337 _string_0f_84_jump_label:  # (payload array byte)
18338     0x11/imm32/alloc-id:fake:payload
18339     # "0f 84/jump-if-="
18340     0xf/imm32/size
18341     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/=
18342 _string_0f_84_jump_break:  # (payload array byte)
18343     0x11/imm32/alloc-id:fake:payload
18344     # "0f 84/jump-if-= break/disp32"
18345     0x1c/imm32/size
18346     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
18347 _string_0f_84_jump_loop:  # (payload array byte)
18348     0x11/imm32/alloc-id:fake:payload
18349     # "0f 84/jump-if-= loop/disp32"
18350     0x1b/imm32/size
18351     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
18352 _string_0f_85_jump_label:  # (payload array byte)
18353     0x11/imm32/alloc-id:fake:payload
18354     # "0f 85/jump-if-!="
18355     0x10/imm32/size
18356     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/=
18357 _string_0f_85_jump_break:  # (payload array byte)
18358     0x11/imm32/alloc-id:fake:payload
18359     # "0f 85/jump-if-!= break/disp32"
18360     0x1d/imm32/size
18361     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
18362 _string_0f_85_jump_loop:  # (payload array byte)
18363     0x11/imm32/alloc-id:fake:payload
18364     # "0f 85/jump-if-!= loop/disp32"
18365     0x1c/imm32/size
18366     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
18367 _string_0f_86_jump_label:  # (payload array byte)
18368     0x11/imm32/alloc-id:fake:payload
18369     # "0f 86/jump-if-addr<="
18370     0x14/imm32/size
18371     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/=
18372 _string_0f_86_jump_break:  # (payload array byte)
18373     0x11/imm32/alloc-id:fake:payload
18374     # "0f 86/jump-if-addr<= break/disp32"
18375     0x21/imm32/size
18376     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
18377 _string_0f_86_jump_loop:  # (payload array byte)
18378     0x11/imm32/alloc-id:fake:payload
18379     # "0f 86/jump-if-addr<= loop/disp32"
18380     0x20/imm32/size
18381     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
18382 _string_0f_87_jump_label:  # (payload array byte)
18383     0x11/imm32/alloc-id:fake:payload
18384     # "0f 87/jump-if-addr>"
18385     0x13/imm32/size
18386     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/>
18387 _string_0f_87_jump_break:  # (payload array byte)
18388     0x11/imm32/alloc-id:fake:payload
18389     # "0f 87/jump-if-addr> break/disp32"
18390     0x20/imm32/size
18391     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
18392 _string_0f_87_jump_loop:  # (payload array byte)
18393     0x11/imm32/alloc-id:fake:payload
18394     # "0f 87/jump-if-addr> loop/disp32"
18395     0x1f/imm32/size
18396     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
18397 _string_0f_8c_jump_label:  # (payload array byte)
18398     0x11/imm32/alloc-id:fake:payload
18399     # "0f 8c/jump-if-<"
18400     0xf/imm32/size
18401     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/<
18402 _string_0f_8c_jump_break:  # (payload array byte)
18403     0x11/imm32/alloc-id:fake:payload
18404     # "0f 8c/jump-if-< break/disp32"
18405     0x1c/imm32/size
18406     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
18407 _string_0f_8c_jump_loop:  # (payload array byte)
18408     0x11/imm32/alloc-id:fake:payload
18409     # "0f 8c/jump-if-< loop/disp32"
18410     0x1b/imm32/size
18411     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
18412 _string_0f_8d_jump_label:  # (payload array byte)
18413     0x11/imm32/alloc-id:fake:payload
18414     # "0f 8d/jump-if->="
18415     0x10/imm32/size
18416     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/=
18417 _string_0f_8d_jump_break:  # (payload array byte)
18418     0x11/imm32/alloc-id:fake:payload
18419     # "0f 8d/jump-if->= break/disp32"
18420     0x1d/imm32/size
18421     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
18422 _string_0f_8d_jump_loop:  # (payload array byte)
18423     0x11/imm32/alloc-id:fake:payload
18424     # "0f 8d/jump-if->= loop/disp32"
18425     0x1c/imm32/size
18426     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
18427 _string_0f_8e_jump_label:  # (payload array byte)
18428     0x11/imm32/alloc-id:fake:payload
18429     # "0f 8e/jump-if-<="
18430     0x10/imm32/size
18431     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/=
18432 _string_0f_8e_jump_break:  # (payload array byte)
18433     0x11/imm32/alloc-id:fake:payload
18434     # "0f 8e/jump-if-<= break/disp32"
18435     0x1d/imm32/size
18436     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
18437 _string_0f_8e_jump_loop:  # (payload array byte)
18438     0x11/imm32/alloc-id:fake:payload
18439     # "0f 8e/jump-if-<= loop/disp32"
18440     0x1c/imm32/size
18441     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
18442 _string_0f_8f_jump_label:  # (payload array byte)
18443     0x11/imm32/alloc-id:fake:payload
18444     # "0f 8f/jump-if->"
18445     0xf/imm32/size
18446     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/>
18447 _string_0f_8f_jump_break:  # (payload array byte)
18448     0x11/imm32/alloc-id:fake:payload
18449     # "0f 8f/jump-if-> break/disp32"
18450     0x1c/imm32/size
18451     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
18452 _string_0f_8f_jump_loop:  # (payload array byte)
18453     0x11/imm32/alloc-id:fake:payload
18454     # "0f 8f/jump-if-> loop/disp32"
18455     0x1b/imm32/size
18456     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
18457 _string_0f_af_multiply:  # (payload array byte)
18458     0x11/imm32/alloc-id:fake:payload
18459     # "0f af/multiply"
18460     0xe/imm32/size
18461     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
18462 _string_21_and_with:  # (payload array byte)
18463     0x11/imm32/alloc-id:fake:payload
18464     # "21/and-with"
18465     0xb/imm32/size
18466     0x32/2 0x31/1 0x2f/slash 0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
18467 _string_23_and:  # (payload array byte)
18468     0x11/imm32/alloc-id:fake:payload
18469     # "23/and"
18470     0x6/imm32/size
18471     0x32/2 0x33/3 0x2f/slash 0x61/a 0x6e/n 0x64/d
18472 _string_25_and_with_eax:  # (payload array byte)
18473     0x11/imm32/alloc-id:fake:payload
18474     # "25/and-with-eax"
18475     0xf/imm32/size
18476     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
18477 _string_29_subtract_from:  # (payload array byte)
18478     0x11/imm32/alloc-id:fake:payload
18479     # "29/subtract-from"
18480     0x10/imm32/size
18481     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
18482 _string_2b_subtract:  # (payload array byte)
18483     0x11/imm32/alloc-id:fake:payload
18484     # "2b/subtract"
18485     0xb/imm32/size
18486     0x32/2 0x62/b 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
18487 _string_2d_subtract_from_eax:  # (payload array byte)
18488     0x11/imm32/alloc-id:fake:payload
18489     # "2d/subtract-from-eax"
18490     0x14/imm32/size
18491     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
18492 _string_31_xor_with:  # (payload array byte)
18493     0x11/imm32/alloc-id:fake:payload
18494     # "31/xor-with"
18495     0xb/imm32/size
18496     0x33/3 0x31/1 0x2f/slash 0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
18497 _string_33_xor:  # (payload array byte)
18498     0x11/imm32/alloc-id:fake:payload
18499     # "33/xor"
18500     0x6/imm32/size
18501     0x33/3 0x33/3 0x2f/slash 0x78/x 0x6f/o 0x72/r
18502 _string_35_xor_with_eax:  # (payload array byte)
18503     0x11/imm32/alloc-id:fake:payload
18504     # "35/xor-with-eax"
18505     0xf/imm32/size
18506     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
18507 _string_39_compare->:  # (payload array byte)
18508     0x11/imm32/alloc-id:fake:payload
18509     # "39/compare->"
18510     0xc/imm32/size
18511     0x33/3 0x39/9 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x2d/dash 0x3e/>
18512 _string_3b_compare<-:  # (payload array byte)
18513     0x11/imm32/alloc-id:fake:payload
18514     # "3b/compare<-"
18515     0xc/imm32/size
18516     0x33/3 0x62/b 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x3c/< 0x2d/dash
18517 _string_3d_compare_eax_with:  # (payload array byte)
18518     0x11/imm32/alloc-id:fake:payload
18519     # "3d/compare-eax-with"
18520     0x13/imm32/size
18521     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
18522 _string_40_increment_eax:  # (payload array byte)
18523     0x11/imm32/alloc-id:fake:payload
18524     # "40/increment-eax"
18525     0x10/imm32/size
18526     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
18527 _string_41_increment_ecx:  # (payload array byte)
18528     0x11/imm32/alloc-id:fake:payload
18529     # "41/increment-ecx"
18530     0x10/imm32/size
18531     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
18532 _string_42_increment_edx:  # (payload array byte)
18533     0x11/imm32/alloc-id:fake:payload
18534     # "42/increment-edx"
18535     0x10/imm32/size
18536     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
18537 _string_43_increment_ebx:  # (payload array byte)
18538     0x11/imm32/alloc-id:fake:payload
18539     # "43/increment-ebx"
18540     0x10/imm32/size
18541     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
18542 _string_46_increment_esi:  # (payload array byte)
18543     0x11/imm32/alloc-id:fake:payload
18544     # "46/increment-esi"
18545     0x10/imm32/size
18546     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
18547 _string_47_increment_edi:  # (payload array byte)
18548     0x11/imm32/alloc-id:fake:payload
18549     # "47/increment-edi"
18550     0x10/imm32/size
18551     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
18552 _string_48_decrement_eax:  # (payload array byte)
18553     0x11/imm32/alloc-id:fake:payload
18554     # "48/decrement-eax"
18555     0x10/imm32/size
18556     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
18557 _string_49_decrement_ecx:  # (payload array byte)
18558     0x11/imm32/alloc-id:fake:payload
18559     # "49/decrement-ecx"
18560     0x10/imm32/size
18561     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
18562 _string_4a_decrement_edx:  # (payload array byte)
18563     0x11/imm32/alloc-id:fake:payload
18564     # "4a/decrement-edx"
18565     0x10/imm32/size
18566     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
18567 _string_4b_decrement_ebx:  # (payload array byte)
18568     0x11/imm32/alloc-id:fake:payload
18569     # "4b/decrement-ebx"
18570     0x10/imm32/size
18571     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
18572 _string_4e_decrement_esi:  # (payload array byte)
18573     0x11/imm32/alloc-id:fake:payload
18574     # "4e/decrement-esi"
18575     0x10/imm32/size
18576     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
18577 _string_4f_decrement_edi:  # (payload array byte)
18578     0x11/imm32/alloc-id:fake:payload
18579     # "4f/decrement-edi"
18580     0x10/imm32/size
18581     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
18582 _string_81_subop_add:  # (payload array byte)
18583     0x11/imm32/alloc-id:fake:payload
18584     # "81 0/subop/add"
18585     0xe/imm32/size
18586     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
18587 _string_81_subop_or:  # (payload array byte)
18588     0x11/imm32/alloc-id:fake:payload
18589     # "81 1/subop/or"
18590     0xd/imm32/size
18591     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
18592 _string_81_subop_and:  # (payload array byte)
18593     0x11/imm32/alloc-id:fake:payload
18594     # "81 4/subop/and"
18595     0xe/imm32/size
18596     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
18597 _string_81_subop_subtract:  # (payload array byte)
18598     0x11/imm32/alloc-id:fake:payload
18599     # "81 5/subop/subtract"
18600     0x13/imm32/size
18601     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
18602 _string_81_subop_xor:  # (payload array byte)
18603     0x11/imm32/alloc-id:fake:payload
18604     # "81 6/subop/xor"
18605     0xe/imm32/size
18606     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
18607 _string_81_subop_compare:  # (payload array byte)
18608     0x11/imm32/alloc-id:fake:payload
18609     # "81 7/subop/compare"
18610     0x12/imm32/size
18611     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
18612 _string_89_<-:  # (payload array byte)
18613     0x11/imm32/alloc-id:fake:payload
18614     # "89/<-"
18615     0x5/imm32/size
18616     0x38/8 0x39/9 0x2f/slash 0x3c/< 0x2d/dash
18617 _string_8b_->:  # (payload array byte)
18618     0x11/imm32/alloc-id:fake:payload
18619     # "8b/->"
18620     0x5/imm32/size
18621     0x38/8 0x62/b 0x2f/slash 0x2d/dash 0x3e/>
18622 _string_8a_copy_byte:
18623     0x11/imm32/alloc-id:fake:payload
18624     # "8a/byte->"
18625     0x9/imm32/size
18626     0x38/8 0x61/a 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x3e/>
18627 _string_88_copy_byte:
18628     0x11/imm32/alloc-id:fake:payload
18629     # "88/byte<-"
18630     0x9/imm32/size
18631     0x38/8 0x38/8 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x3c/< 0x2d/-
18632 _string_8d_copy_address:  # (payload array byte)
18633     0x11/imm32/alloc-id:fake:payload
18634     # "8d/copy-address"
18635     0xf/imm32/size
18636     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
18637 _string_b8_copy_to_eax:  # (payload array byte)
18638     0x11/imm32/alloc-id:fake:payload
18639     # "b8/copy-to-eax"
18640     0xe/imm32/size
18641     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
18642 _string_b9_copy_to_ecx:  # (payload array byte)
18643     0x11/imm32/alloc-id:fake:payload
18644     # "b9/copy-to-ecx"
18645     0xe/imm32/size
18646     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
18647 _string_ba_copy_to_edx:  # (payload array byte)
18648     0x11/imm32/alloc-id:fake:payload
18649     # "ba/copy-to-edx"
18650     0xe/imm32/size
18651     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
18652 _string_bb_copy_to_ebx:  # (payload array byte)
18653     0x11/imm32/alloc-id:fake:payload
18654     # "bb/copy-to-ebx"
18655     0xe/imm32/size
18656     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
18657 _string_be_copy_to_esi:  # (payload array byte)
18658     0x11/imm32/alloc-id:fake:payload
18659     # "be/copy-to-esi"
18660     0xe/imm32/size
18661     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
18662 _string_bf_copy_to_edi:  # (payload array byte)
18663     0x11/imm32/alloc-id:fake:payload
18664     # "bf/copy-to-edi"
18665     0xe/imm32/size
18666     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
18667 _string_c7_subop_copy:  # (payload array byte)
18668     0x11/imm32/alloc-id:fake:payload
18669     # "c7 0/subop/copy"
18670     0xf/imm32/size
18671     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
18672 _string_e9_jump_label:  # (payload array byte)
18673     0x11/imm32/alloc-id:fake:payload
18674     # "e9/jump"
18675     0x7/imm32/size
18676     0x65/e 0x39/9 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p
18677 _string_e9_jump_break:  # (payload array byte)
18678     0x11/imm32/alloc-id:fake:payload
18679     # "e9/jump break/disp32"
18680     0x14/imm32/size
18681     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
18682 _string_e9_jump_loop:  # (payload array byte)
18683     0x11/imm32/alloc-id:fake:payload
18684     # "e9/jump loop/disp32"
18685     0x13/imm32/size
18686     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
18687 _string_ff_subop_increment:  # (payload array byte)
18688     0x11/imm32/alloc-id:fake:payload
18689     # "ff 0/subop/increment"
18690     0x14/imm32/size
18691     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
18692 _string_ff_subop_decrement:  # (payload array byte)
18693     0x11/imm32/alloc-id:fake:payload
18694     # "ff 1/subop/decrement"
18695     0x14/imm32/size
18696     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
18697 _string_c1_subop_shift_left:  # (payload array byte)
18698     0x11/imm32/alloc-id:fake:payload
18699     # "c1/shift 4/subop/left"
18700     0x15/imm32/size
18701     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
18702 _string_c1_subop_shift_right_padding_zeroes:  # (payload array byte)
18703     0x11/imm32/alloc-id:fake:payload
18704     # "c1/shift 5/subop/right-padding-zeroes"
18705     0x25/imm32/size
18706     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
18707 _string_c1_subop_shift_right_preserving_sign:  # (payload array byte)
18708     0x11/imm32/alloc-id:fake:payload
18709     # "c1/shift 7/subop/right-preserving-sign"
18710     0x26/imm32/size
18711     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
18712 
18713 Single-int-var-in-mem:  # (payload list var)
18714     0x11/imm32/alloc-id:fake:payload
18715     0x11/imm32/alloc-id:fake
18716     Int-var-in-mem/imm32
18717     0/imm32/next
18718     0/imm32/next
18719 
18720 Int-var-in-mem:  # (payload var)
18721     0x11/imm32/alloc-id:fake:payload
18722     0/imm32/name
18723     0/imm32/name
18724     0x11/imm32/alloc-id:fake
18725     Type-int/imm32
18726     1/imm32/some-block-depth
18727     1/imm32/some-stack-offset
18728     0/imm32/no-register
18729     0/imm32/no-register
18730 
18731 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
18732 Single-byte-var-in-mem:  # (payload list var)
18733     0x11/imm32/alloc-id:fake:payload
18734     0x11/imm32/alloc-id:fake
18735     Byte-var-in-mem/imm32
18736     0/imm32/next
18737     0/imm32/next
18738 
18739 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
18740 Byte-var-in-mem:  # (payload var)
18741     0x11/imm32/alloc-id:fake:payload
18742     0/imm32/name
18743     0/imm32/name
18744     0x11/imm32/alloc-id:fake
18745     Type-byte/imm32
18746     1/imm32/some-block-depth
18747     1/imm32/some-stack-offset
18748     0/imm32/no-register
18749     0/imm32/no-register
18750 
18751 Two-args-int-stack-int-reg:  # (payload list var)
18752     0x11/imm32/alloc-id:fake:payload
18753     0x11/imm32/alloc-id:fake
18754     Int-var-in-mem/imm32
18755     0x11/imm32/alloc-id:fake
18756     Single-int-var-in-some-register/imm32/next
18757 
18758 Two-int-args-in-regs:  # (payload list var)
18759     0x11/imm32/alloc-id:fake:payload
18760     0x11/imm32/alloc-id:fake
18761     Int-var-in-some-register/imm32
18762     0x11/imm32/alloc-id:fake
18763     Single-int-var-in-some-register/imm32/next
18764 
18765 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
18766 Two-args-byte-stack-byte-reg:  # (payload list var)
18767     0x11/imm32/alloc-id:fake:payload
18768     0x11/imm32/alloc-id:fake
18769     Byte-var-in-mem/imm32
18770     0x11/imm32/alloc-id:fake
18771     Single-byte-var-in-some-register/imm32/next
18772 
18773 Two-args-int-reg-int-stack:  # (payload list var)
18774     0x11/imm32/alloc-id:fake:payload
18775     0x11/imm32/alloc-id:fake
18776     Int-var-in-some-register/imm32
18777     0x11/imm32/alloc-id:fake
18778     Single-int-var-in-mem/imm32/next
18779 
18780 Two-args-int-eax-int-literal:  # (payload list var)
18781     0x11/imm32/alloc-id:fake:payload
18782     0x11/imm32/alloc-id:fake
18783     Int-var-in-eax/imm32
18784     0x11/imm32/alloc-id:fake
18785     Single-lit-var/imm32/next
18786 
18787 Int-var-and-literal:  # (payload list var)
18788     0x11/imm32/alloc-id:fake:payload
18789     0x11/imm32/alloc-id:fake
18790     Int-var-in-mem/imm32
18791     0x11/imm32/alloc-id:fake
18792     Single-lit-var/imm32/next
18793 
18794 Int-var-in-register-and-literal:  # (payload list var)
18795     0x11/imm32/alloc-id:fake:payload
18796     0x11/imm32/alloc-id:fake
18797     Int-var-in-some-register/imm32
18798     0x11/imm32/alloc-id:fake
18799     Single-lit-var/imm32/next
18800 
18801 Single-int-var-in-some-register:  # (payload list var)
18802     0x11/imm32/alloc-id:fake:payload
18803     0x11/imm32/alloc-id:fake
18804     Int-var-in-some-register/imm32
18805     0/imm32/next
18806     0/imm32/next
18807 
18808 Single-addr-var-in-some-register:  # (payload list var)
18809     0x11/imm32/alloc-id:fake:payload
18810     0x11/imm32/alloc-id:fake
18811     Addr-var-in-some-register/imm32
18812     0/imm32/next
18813     0/imm32/next
18814 
18815 Single-byte-var-in-some-register:  # (payload list var)
18816     0x11/imm32/alloc-id:fake:payload
18817     0x11/imm32/alloc-id:fake
18818     Byte-var-in-some-register/imm32
18819     0/imm32/next
18820     0/imm32/next
18821 
18822 Int-var-in-some-register:  # (payload var)
18823     0x11/imm32/alloc-id:fake:payload
18824     0/imm32/name
18825     0/imm32/name
18826     0x11/imm32/alloc-id:fake
18827     Type-int/imm32
18828     1/imm32/some-block-depth
18829     0/imm32/no-stack-offset
18830     0x11/imm32/alloc-id:fake
18831     Any-register/imm32
18832 
18833 Any-register:  # (payload array byte)
18834     0x11/imm32/alloc-id:fake:payload
18835     1/imm32/size
18836     # data
18837     2a/asterisk
18838 
18839 Addr-var-in-some-register:  # (payload var)
18840     0x11/imm32/alloc-id:fake:payload
18841     0/imm32/name
18842     0/imm32/name
18843     0x11/imm32/alloc-id:fake
18844     Type-addr/imm32
18845     1/imm32/some-block-depth
18846     0/imm32/no-stack-offset
18847     0x11/imm32/alloc-id:fake
18848     Any-register/imm32
18849 
18850 Byte-var-in-some-register:  # (payload var)
18851     0x11/imm32/alloc-id:fake:payload
18852     0/imm32/name
18853     0/imm32/name
18854     0x11/imm32/alloc-id:fake
18855     Type-byte/imm32
18856     1/imm32/some-block-depth
18857     0/imm32/no-stack-offset
18858     0x11/imm32/alloc-id:fake
18859     Any-register/imm32
18860 
18861 Single-int-var-in-eax:  # (payload list var)
18862     0x11/imm32/alloc-id:fake:payload
18863     0x11/imm32/alloc-id:fake
18864     Int-var-in-eax/imm32
18865     0/imm32/next
18866     0/imm32/next
18867 
18868 Int-var-in-eax:
18869     0x11/imm32/alloc-id:fake:payload
18870     0/imm32/name
18871     0/imm32/name
18872     0x11/imm32/alloc-id:fake
18873     Type-int/imm32
18874     1/imm32/some-block-depth
18875     0/imm32/no-stack-offset
18876     0x11/imm32/alloc-id:fake
18877     $Register-eax/imm32
18878 
18879 Single-int-var-in-ecx:  # (payload list var)
18880     0x11/imm32/alloc-id:fake:payload
18881     0x11/imm32/alloc-id:fake
18882     Int-var-in-ecx/imm32
18883     0/imm32/next
18884     0/imm32/next
18885 
18886 Int-var-in-ecx:
18887     0x11/imm32/alloc-id:fake:payload
18888     0/imm32/name
18889     0/imm32/name
18890     0x11/imm32/alloc-id:fake
18891     Type-int/imm32
18892     1/imm32/some-block-depth
18893     0/imm32/no-stack-offset
18894     0x11/imm32/alloc-id:fake
18895     $Register-ecx/imm32/register
18896 
18897 Single-int-var-in-edx:  # (payload list var)
18898     0x11/imm32/alloc-id:fake:payload
18899     0x11/imm32/alloc-id:fake
18900     Int-var-in-edx/imm32
18901     0/imm32/next
18902     0/imm32/next
18903 
18904 Int-var-in-edx:  # (payload list var)
18905     0x11/imm32/alloc-id:fake:payload
18906     0/imm32/name
18907     0/imm32/name
18908     0x11/imm32/alloc-id:fake
18909     Type-int/imm32
18910     1/imm32/some-block-depth
18911     0/imm32/no-stack-offset
18912     0x11/imm32/alloc-id:fake
18913     $Register-edx/imm32/register
18914 
18915 Single-int-var-in-ebx:  # (payload list var)
18916     0x11/imm32/alloc-id:fake:payload
18917     0x11/imm32/alloc-id:fake
18918     Int-var-in-ebx/imm32
18919     0/imm32/next
18920     0/imm32/next
18921 
18922 Int-var-in-ebx:  # (payload list var)
18923     0x11/imm32/alloc-id:fake:payload
18924     0/imm32/name
18925     0/imm32/name
18926     0x11/imm32/alloc-id:fake
18927     Type-int/imm32
18928     1/imm32/some-block-depth
18929     0/imm32/no-stack-offset
18930     0x11/imm32/alloc-id:fake
18931     $Register-ebx/imm32/register
18932 
18933 Single-int-var-in-esi:  # (payload list var)
18934     0x11/imm32/alloc-id:fake:payload
18935     0x11/imm32/alloc-id:fake
18936     Int-var-in-esi/imm32
18937     0/imm32/next
18938     0/imm32/next
18939 
18940 Int-var-in-esi:  # (payload list var)
18941     0x11/imm32/alloc-id:fake:payload
18942     0/imm32/name
18943     0/imm32/name
18944     0x11/imm32/alloc-id:fake
18945     Type-int/imm32
18946     1/imm32/some-block-depth
18947     0/imm32/no-stack-offset
18948     0x11/imm32/alloc-id:fake
18949     $Register-esi/imm32/register
18950 
18951 Single-int-var-in-edi:  # (payload list var)
18952     0x11/imm32/alloc-id:fake:payload
18953     0x11/imm32/alloc-id:fake
18954     Int-var-in-edi/imm32
18955     0/imm32/next
18956     0/imm32/next
18957 
18958 Int-var-in-edi:  # (payload list var)
18959     0x11/imm32/alloc-id:fake:payload
18960     0/imm32/name
18961     0/imm32/name
18962     0x11/imm32/alloc-id:fake
18963     Type-int/imm32
18964     1/imm32/some-block-depth
18965     0/imm32/no-stack-offset
18966     0x11/imm32/alloc-id:fake
18967     $Register-edi/imm32/register
18968 
18969 Single-lit-var:  # (payload list var)
18970     0x11/imm32/alloc-id:fake:payload
18971     0x11/imm32/alloc-id:fake
18972     Lit-var/imm32
18973     0/imm32/next
18974     0/imm32/next
18975 
18976 Lit-var:  # (payload var)
18977     0x11/imm32/alloc-id:fake:payload
18978     0/imm32/name
18979     0/imm32/name
18980     0x11/imm32/alloc-id:fake
18981     Type-literal/imm32
18982     1/imm32/some-block-depth
18983     0/imm32/no-stack-offset
18984     0/imm32/no-register
18985     0/imm32/no-register
18986 
18987 Type-int:  # (payload type-tree)
18988     0x11/imm32/alloc-id:fake:payload
18989     1/imm32/is-atom
18990     1/imm32/value:int
18991     0/imm32/left:unused
18992     0/imm32/right:null
18993     0/imm32/right:null
18994 
18995 Type-literal:  # (payload type-tree)
18996     0x11/imm32/alloc-id:fake:payload
18997     1/imm32/is-atom
18998     0/imm32/value:literal
18999     0/imm32/left:unused
19000     0/imm32/right:null
19001     0/imm32/right:null
19002 
19003 Type-addr:  # (payload type-tree)
19004     0x11/imm32/alloc-id:fake:payload
19005     1/imm32/is-atom
19006     2/imm32/value:addr
19007     0/imm32/left:unused
19008     0/imm32/right:null
19009     0/imm32/right:null
19010 
19011 Type-byte:  # (payload type-tree)
19012     0x11/imm32/alloc-id:fake:payload
19013     1/imm32/is-atom
19014     8/imm32/value:byte
19015     0/imm32/left:unused
19016     0/imm32/right:null
19017     0/imm32/right:null
19018 
19019 == code
19020 emit-subx-primitive:  # out: (addr buffered-file), stmt: (addr stmt), primitive: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
19021     # . prologue
19022     55/push-ebp
19023     89/<- %ebp 4/r32/esp
19024     # . save registers
19025     50/push-eax
19026     51/push-ecx
19027     # ecx = primitive
19028     8b/-> *(ebp+0x10) 1/r32/ecx
19029     # emit primitive name
19030     (emit-indent *(ebp+8) *Curr-block-depth)
19031     (lookup *(ecx+0x18) *(ecx+0x1c))  # Primitive-subx-name Primitive-subx-name => eax
19032     (write-buffered *(ebp+8) %eax)
19033     # emit rm32 if necessary
19034     (emit-subx-rm32 *(ebp+8) *(ecx+0x20) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-rm32
19035     # emit r32 if necessary
19036     (emit-subx-r32 *(ebp+8) *(ecx+0x24) *(ebp+0xc))  # Primitive-subx-r32
19037     # emit imm32 if necessary
19038     (emit-subx-imm32 *(ebp+8) *(ecx+0x28) *(ebp+0xc))  # Primitive-subx-imm32
19039     # emit imm8 if necessary
19040     (emit-subx-imm8 *(ebp+8) *(ecx+0x2c) *(ebp+0xc))  # Primitive-subx-imm8
19041     # emit disp32 if necessary
19042     (emit-subx-disp32 *(ebp+8) *(ecx+0x30) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-disp32
19043     (write-buffered *(ebp+8) Newline)
19044 $emit-subx-primitive:end:
19045     # . restore registers
19046     59/pop-to-ecx
19047     58/pop-to-eax
19048     # . epilogue
19049     89/<- %esp 5/r32/ebp
19050     5d/pop-to-ebp
19051     c3/return
19052 
19053 emit-subx-rm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
19054     # . prologue
19055     55/push-ebp
19056     89/<- %ebp 4/r32/esp
19057     # . save registers
19058     50/push-eax
19059     # if (l == 0) return
19060     81 7/subop/compare *(ebp+0xc) 0/imm32
19061     74/jump-if-= $emit-subx-rm32:end/disp8
19062     # var v/eax: (addr stmt-var)
19063     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
19064     (emit-subx-var-as-rm32 *(ebp+8) %eax)
19065 $emit-subx-rm32:end:
19066     # . restore registers
19067     58/pop-to-eax
19068     # . epilogue
19069     89/<- %esp 5/r32/ebp
19070     5d/pop-to-ebp
19071     c3/return
19072 
19073 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)
19074     # . prologue
19075     55/push-ebp
19076     89/<- %ebp 4/r32/esp
19077     # . save registers
19078     51/push-ecx
19079     # eax = l
19080     8b/-> *(ebp+0xc) 0/r32/eax
19081     # ecx = stmt
19082     8b/-> *(ebp+8) 1/r32/ecx
19083     # if (l == 1) return stmt->inouts
19084     {
19085       3d/compare-eax-and 1/imm32
19086       75/jump-if-!= break/disp8
19087 $get-stmt-operand-from-arg-location:1:
19088       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
19089       eb/jump $get-stmt-operand-from-arg-location:end/disp8
19090     }
19091     # if (l == 2) return stmt->inouts->next
19092     {
19093       3d/compare-eax-and 2/imm32
19094       75/jump-if-!= break/disp8
19095 $get-stmt-operand-from-arg-location:2:
19096       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
19097       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
19098       eb/jump $get-stmt-operand-from-arg-location:end/disp8
19099     }
19100     # if (l == 3) return stmt->outputs
19101     {
19102       3d/compare-eax-and 3/imm32
19103       75/jump-if-!= break/disp8
19104 $get-stmt-operand-from-arg-location:3:
19105       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
19106       eb/jump $get-stmt-operand-from-arg-location:end/disp8
19107     }
19108     # abort
19109     e9/jump $get-stmt-operand-from-arg-location:abort/disp32
19110 $get-stmt-operand-from-arg-location:end:
19111     # . restore registers
19112     59/pop-to-ecx
19113     # . epilogue
19114     89/<- %esp 5/r32/ebp
19115     5d/pop-to-ebp
19116     c3/return
19117 
19118 $get-stmt-operand-from-arg-location:abort:
19119     # error("invalid arg-location " eax)
19120     (write-buffered *(ebp+0x10) "invalid arg-location ")
19121     (write-int32-hex-buffered *(ebp+0x10) %eax)
19122     (write-buffered *(ebp+0x10) Newline)
19123     (flush *(ebp+0x10))
19124     (stop *(ebp+0x14) 1)
19125     # never gets here
19126 
19127 emit-subx-r32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
19128     # . prologue
19129     55/push-ebp
19130     89/<- %ebp 4/r32/esp
19131     # . save registers
19132     50/push-eax
19133     51/push-ecx
19134     # if (l == 0) return
19135     81 7/subop/compare *(ebp+0xc) 0/imm32
19136     0f 84/jump-if-= $emit-subx-r32:end/disp32
19137     # var v/eax: (addr stmt-var)
19138     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
19139     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
19140     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
19141     (maybe-get Mu-registers %eax 0xc)  # => eax: (addr register-index)
19142     (write-buffered *(ebp+8) Space)
19143     (write-int32-hex-buffered *(ebp+8) *eax)
19144     (write-buffered *(ebp+8) "/r32")
19145 $emit-subx-r32:end:
19146     # . restore registers
19147     59/pop-to-ecx
19148     58/pop-to-eax
19149     # . epilogue
19150     89/<- %esp 5/r32/ebp
19151     5d/pop-to-ebp
19152     c3/return
19153 
19154 emit-subx-imm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
19155     # . prologue
19156     55/push-ebp
19157     89/<- %ebp 4/r32/esp
19158     # . save registers
19159     50/push-eax
19160     51/push-ecx
19161     # if (l == 0) return
19162     81 7/subop/compare *(ebp+0xc) 0/imm32
19163     0f 84/jump-if-= $emit-subx-imm32:end/disp32
19164     # var v/eax: (handle var)
19165     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
19166     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
19167     (lookup *eax *(eax+4))  # Var-name Var-name => eax
19168     (write-buffered *(ebp+8) Space)
19169     (write-buffered *(ebp+8) %eax)
19170     (write-buffered *(ebp+8) "/imm32")
19171 $emit-subx-imm32:end:
19172     # . restore registers
19173     59/pop-to-ecx
19174     58/pop-to-eax
19175     # . epilogue
19176     89/<- %esp 5/r32/ebp
19177     5d/pop-to-ebp
19178     c3/return
19179 
19180 emit-subx-imm8:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
19181     # . prologue
19182     55/push-ebp
19183     89/<- %ebp 4/r32/esp
19184     # . save registers
19185     50/push-eax
19186     51/push-ecx
19187     # if (l == 0) return
19188     81 7/subop/compare *(ebp+0xc) 0/imm32
19189     0f 84/jump-if-= $emit-subx-imm32:end/disp32
19190     # var v/eax: (handle var)
19191     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
19192     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
19193     (lookup *eax *(eax+4))  # Var-name Var-name => eax
19194     (write-buffered *(ebp+8) Space)
19195     (write-buffered *(ebp+8) %eax)
19196     (write-buffered *(ebp+8) "/imm8")
19197 $emit-subx-imm8:end:
19198     # . restore registers
19199     59/pop-to-ecx
19200     58/pop-to-eax
19201     # . epilogue
19202     89/<- %esp 5/r32/ebp
19203     5d/pop-to-ebp
19204     c3/return
19205 
19206 emit-subx-disp32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
19207     # . prologue
19208     55/push-ebp
19209     89/<- %ebp 4/r32/esp
19210     # . save registers
19211     50/push-eax
19212     51/push-ecx
19213     # if (location == 0) return
19214     81 7/subop/compare *(ebp+0xc) 0/imm32
19215     0f 84/jump-if-= $emit-subx-disp32:end/disp32
19216     # var v/eax: (addr stmt-var)
19217     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
19218     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
19219     (lookup *eax *(eax+4))  # Var-name Var-name => eax
19220     (write-buffered *(ebp+8) Space)
19221     (write-buffered *(ebp+8) %eax)
19222     # hack: if instruction operation starts with "break", emit ":break"
19223     # var name/ecx: (addr array byte) = lookup(stmt->operation)
19224     8b/-> *(ebp+0x10) 0/r32/eax
19225     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
19226     89/<- %ecx 0/r32/eax
19227     {
19228       (string-starts-with? %ecx "break")  # => eax
19229       3d/compare-eax-and 0/imm32/false
19230       74/jump-if-= break/disp8
19231       (write-buffered *(ebp+8) ":break")
19232     }
19233     # hack: if instruction operation starts with "loop", emit ":loop"
19234     {
19235       (string-starts-with? %ecx "loop")  # => eax
19236       3d/compare-eax-and 0/imm32/false
19237       74/jump-if-= break/disp8
19238       (write-buffered *(ebp+8) ":loop")
19239     }
19240     (write-buffered *(ebp+8) "/disp32")
19241 $emit-subx-disp32:end:
19242     # . restore registers
19243     59/pop-to-ecx
19244     58/pop-to-eax
19245     # . epilogue
19246     89/<- %esp 5/r32/ebp
19247     5d/pop-to-ebp
19248     c3/return
19249 
19250 emit-call:  # out: (addr buffered-file), stmt: (addr stmt)
19251     # . prologue
19252     55/push-ebp
19253     89/<- %ebp 4/r32/esp
19254     # . save registers
19255     50/push-eax
19256     51/push-ecx
19257     #
19258     (emit-indent *(ebp+8) *Curr-block-depth)
19259     (write-buffered *(ebp+8) "(")
19260     # ecx = stmt
19261     8b/-> *(ebp+0xc) 1/r32/ecx
19262     # - emit function name
19263     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
19264     (write-buffered *(ebp+8) %eax)
19265     # - emit arguments
19266     # var curr/eax: (addr stmt-var) = lookup(stmt->inouts)
19267     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
19268     {
19269       # if (curr == null) break
19270       3d/compare-eax-and 0/imm32
19271       74/jump-if-= break/disp8
19272       #
19273       (emit-subx-call-operand *(ebp+8) %eax)
19274       # curr = lookup(curr->next)
19275       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
19276       eb/jump loop/disp8
19277     }
19278     #
19279     (write-buffered *(ebp+8) ")\n")
19280 $emit-call:end:
19281     # . restore registers
19282     59/pop-to-ecx
19283     58/pop-to-eax
19284     # . epilogue
19285     89/<- %esp 5/r32/ebp
19286     5d/pop-to-ebp
19287     c3/return
19288 
19289 emit-subx-call-operand:  # out: (addr buffered-file), s: (addr stmt-var)
19290     # shares code with emit-subx-var-as-rm32
19291     # . prologue
19292     55/push-ebp
19293     89/<- %ebp 4/r32/esp
19294     # . save registers
19295     50/push-eax
19296     51/push-ecx
19297     56/push-esi
19298     # ecx = s
19299     8b/-> *(ebp+0xc) 1/r32/ecx
19300     # var operand/esi: (addr var) = lookup(s->value)
19301     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
19302     89/<- %esi 0/r32/eax
19303     # if (operand->register && !s->is-deref?) emit "%__"
19304     {
19305 $emit-subx-call-operand:check-for-register-direct:
19306       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
19307       74/jump-if-= break/disp8
19308       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
19309       75/jump-if-!= break/disp8
19310 $emit-subx-call-operand:register-direct:
19311       (write-buffered *(ebp+8) " %")
19312       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
19313       (write-buffered *(ebp+8) %eax)
19314       e9/jump $emit-subx-call-operand:end/disp32
19315     }
19316     # else if (operand->register && s->is-deref?) emit "*__"
19317     {
19318 $emit-subx-call-operand:check-for-register-indirect:
19319       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
19320       74/jump-if-= break/disp8
19321       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
19322       74/jump-if-= break/disp8
19323 $emit-subx-call-operand:register-indirect:
19324       (emit-subx-call-operand-register-indirect *(ebp+8) %esi)
19325       e9/jump $emit-subx-call-operand:end/disp32
19326     }
19327     # else if (operand->stack-offset) emit "*(ebp+__)"
19328     {
19329       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
19330       74/jump-if-= break/disp8
19331 $emit-subx-call-operand:stack:
19332       (emit-subx-call-operand-stack *(ebp+8) %esi)
19333       e9/jump $emit-subx-call-operand:end/disp32
19334     }
19335     # else if (operand->type == literal) emit "__"
19336     {
19337       (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
19338       81 7/subop/compare *(eax+4) 0/imm32  # Type-tree-left
19339       75/jump-if-!= break/disp8
19340 $emit-subx-call-operand:literal:
19341       (write-buffered *(ebp+8) Space)
19342       (lookup *esi *(esi+4))  # Var-name Var-name => eax
19343       (write-buffered *(ebp+8) %eax)
19344     }
19345 $emit-subx-call-operand:end:
19346     # . restore registers
19347     5e/pop-to-esi
19348     59/pop-to-ecx
19349     58/pop-to-eax
19350     # . epilogue
19351     89/<- %esp 5/r32/ebp
19352     5d/pop-to-ebp
19353     c3/return
19354 
19355 emit-subx-call-operand-register-indirect:  # out: (addr buffered-file), v: (addr var)
19356     # . prologue
19357     55/push-ebp
19358     89/<- %ebp 4/r32/esp
19359     # . save registers
19360     50/push-eax
19361     51/push-ecx
19362     56/push-esi
19363     # esi = v
19364     8b/-> *(ebp+0xc) 6/r32/esi
19365     # var size/ecx: int = size-of-deref(v)
19366     (size-of-deref %esi)  # => eax
19367     89/<- %ecx 0/r32/eax
19368     # var reg-name/esi: (addr array byte) = lookup(v->register)
19369     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
19370     89/<- %esi 0/r32/eax
19371     # TODO: assert size is a multiple of 4
19372     # var i/eax: int = 0
19373     b8/copy-to-eax 0/imm32
19374     {
19375 $emit-subx-call-operand-register-indirect:loop:
19376       # if (i >= size) break
19377       39/compare %eax 1/r32/ecx
19378       7d/jump-if->= break/disp8
19379       # emit " *(" v->register "+" i ")"
19380       (write-buffered *(ebp+8) " *(")
19381       (write-buffered *(ebp+8) %esi)
19382       (write-buffered *(ebp+8) "+")
19383       (write-int32-hex-buffered *(ebp+8) %eax)
19384       (write-buffered *(ebp+8) ")")
19385       # i += 4
19386       05/add-to-eax 4/imm32
19387       #
19388       eb/jump loop/disp8
19389     }
19390 $emit-subx-call-operand-register-indirect:end:
19391     # . restore registers
19392     5e/pop-to-esi
19393     59/pop-to-ecx
19394     58/pop-to-eax
19395     # . epilogue
19396     89/<- %esp 5/r32/ebp
19397     5d/pop-to-ebp
19398     c3/return
19399 
19400 emit-subx-call-operand-stack:  # out: (addr buffered-file), v: (addr var)
19401     # . prologue
19402     55/push-ebp
19403     89/<- %ebp 4/r32/esp
19404     # . save registers
19405     50/push-eax
19406     51/push-ecx
19407     56/push-esi
19408     # esi = v
19409     8b/-> *(ebp+0xc) 6/r32/esi
19410     # var curr/ecx: int = v->offset
19411     8b/-> *(esi+0x14) 1/r32/ecx  # Var-offset
19412     # var max/eax: int = v->offset + size-of(v)
19413     (size-of %esi)  # => eax
19414     # TODO: assert size is a multiple of 4
19415     01/add-to %eax 1/r32/ecx
19416     {
19417 $emit-subx-call-operand-stack:loop:
19418       # if (curr >= max) break
19419       39/compare %ecx 0/r32/eax
19420       7d/jump-if->= break/disp8
19421       # emit " *(ebp+" curr ")"
19422       (write-buffered *(ebp+8) " *(ebp+")
19423       (write-int32-hex-buffered *(ebp+8) %ecx)
19424       (write-buffered *(ebp+8) ")")
19425       # i += 4
19426       81 0/subop/add %ecx 4/imm32
19427       #
19428       eb/jump loop/disp8
19429     }
19430 $emit-subx-call-operand-stack:end:
19431     # . restore registers
19432     5e/pop-to-esi
19433     59/pop-to-ecx
19434     58/pop-to-eax
19435     # . epilogue
19436     89/<- %esp 5/r32/ebp
19437     5d/pop-to-ebp
19438     c3/return
19439 
19440 emit-subx-var-as-rm32:  # out: (addr buffered-file), s: (addr stmt-var)
19441     # . prologue
19442     55/push-ebp
19443     89/<- %ebp 4/r32/esp
19444     # . save registers
19445     50/push-eax
19446     51/push-ecx
19447     56/push-esi
19448     # ecx = s
19449     8b/-> *(ebp+0xc) 1/r32/ecx
19450     # var operand/esi: (addr var) = lookup(s->value)
19451     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
19452     89/<- %esi 0/r32/eax
19453     # if (operand->register && s->is-deref?) emit "*__"
19454     {
19455 $emit-subx-var-as-rm32:check-for-register-indirect:
19456       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
19457       74/jump-if-= break/disp8
19458       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
19459       74/jump-if-= break/disp8
19460 $emit-subx-var-as-rm32:register-indirect:
19461       (write-buffered *(ebp+8) " *")
19462       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
19463       (write-buffered *(ebp+8) %eax)
19464       e9/jump $emit-subx-var-as-rm32:end/disp32
19465     }
19466     # if (operand->register && !s->is-deref?) emit "%__"
19467     {
19468 $emit-subx-var-as-rm32:check-for-register-direct:
19469       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
19470       74/jump-if-= break/disp8
19471       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
19472       75/jump-if-!= break/disp8
19473 $emit-subx-var-as-rm32:register-direct:
19474       (write-buffered *(ebp+8) " %")
19475       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
19476       (write-buffered *(ebp+8) %eax)
19477       e9/jump $emit-subx-var-as-rm32:end/disp32
19478     }
19479     # else if (operand->stack-offset) emit "*(ebp+__)"
19480     {
19481       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
19482       74/jump-if-= break/disp8
19483 $emit-subx-var-as-rm32:stack:
19484       (write-buffered *(ebp+8) Space)
19485       (write-buffered *(ebp+8) "*(ebp+")
19486       (write-int32-hex-buffered *(ebp+8) *(esi+0x14))  # Var-offset
19487       (write-buffered *(ebp+8) ")")
19488     }
19489 $emit-subx-var-as-rm32:end:
19490     # . restore registers
19491     5e/pop-to-esi
19492     59/pop-to-ecx
19493     58/pop-to-eax
19494     # . epilogue
19495     89/<- %esp 5/r32/ebp
19496     5d/pop-to-ebp
19497     c3/return
19498 
19499 find-matching-primitive:  # primitives: (addr primitive), stmt: (addr stmt) -> result/eax: (addr primitive)
19500     # . prologue
19501     55/push-ebp
19502     89/<- %ebp 4/r32/esp
19503     # . save registers
19504     51/push-ecx
19505     # var curr/ecx: (addr primitive) = primitives
19506     8b/-> *(ebp+8) 1/r32/ecx
19507     {
19508 $find-matching-primitive:loop:
19509       # if (curr == null) break
19510       81 7/subop/compare %ecx 0/imm32
19511       74/jump-if-= break/disp8
19512       # if match(curr, stmt) return curr
19513       {
19514         (mu-stmt-matches-primitive? *(ebp+0xc) %ecx)  # => eax
19515         3d/compare-eax-and 0/imm32/false
19516         74/jump-if-= break/disp8
19517         89/<- %eax 1/r32/ecx
19518         eb/jump $find-matching-primitive:end/disp8
19519       }
19520 $find-matching-primitive:next-primitive:
19521       # curr = curr->next
19522       (lookup *(ecx+0x38) *(ecx+0x3c))  # Primitive-next Primitive-next => eax
19523       89/<- %ecx 0/r32/eax
19524       #
19525       e9/jump loop/disp32
19526     }
19527     # return null
19528     b8/copy-to-eax 0/imm32
19529 $find-matching-primitive:end:
19530     # . restore registers
19531     59/pop-to-ecx
19532     # . epilogue
19533     89/<- %esp 5/r32/ebp
19534     5d/pop-to-ebp
19535     c3/return
19536 
19537 mu-stmt-matches-primitive?:  # stmt: (addr stmt), primitive: (addr primitive) -> result/eax: boolean
19538     # A mu stmt matches a primitive if the name matches, all the inout vars
19539     # match, and all the output vars match.
19540     # Vars match if types match and registers match.
19541     # In addition, a stmt output matches a primitive's output if types match
19542     # and the primitive has a wildcard register.
19543     # . prologue
19544     55/push-ebp
19545     89/<- %ebp 4/r32/esp
19546     # . save registers
19547     51/push-ecx
19548     52/push-edx
19549     53/push-ebx
19550     56/push-esi
19551     57/push-edi
19552     # ecx = stmt
19553     8b/-> *(ebp+8) 1/r32/ecx
19554     # edx = primitive
19555     8b/-> *(ebp+0xc) 2/r32/edx
19556     {
19557 $mu-stmt-matches-primitive?:check-name:
19558       # if (primitive->name != stmt->operation) return false
19559       # . var esi: (addr array byte) = lookup(stmt->operation)
19560       (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
19561       89/<- %esi 0/r32/eax
19562       # . var edi: (addr array byte) = lookup(primitive->name)
19563       (lookup *edx *(edx+4))  # Primitive-name Primitive-name => eax
19564       89/<- %edi 0/r32/eax
19565       (string-equal? %esi %edi)  # => eax
19566       3d/compare-eax-and 0/imm32/false
19567       75/jump-if-!= break/disp8
19568       b8/copy-to-eax 0/imm32
19569       e9/jump $mu-stmt-matches-primitive?:end/disp32
19570     }
19571     # var curr/esi: (addr stmt-var) = lookup(stmt->inouts)
19572     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
19573     89/<- %esi 0/r32/eax
19574     # var curr2/edi: (addr list var) = lookup(primitive->inouts)
19575     (lookup *(edx+8) *(edx+0xc))  # Primitive-inouts Primitive-inouts => eax
19576     89/<- %edi 0/r32/eax
19577     {
19578 $mu-stmt-matches-primitive?:inouts-loop:
19579       # if (curr == 0 && curr2 == 0) move on to check outputs
19580       {
19581 $mu-stmt-matches-primitive?:check-both-inouts-null:
19582         81 7/subop/compare %esi 0/imm32
19583         75/jump-if-!= break/disp8
19584 $mu-stmt-matches-primitive?:stmt-inout-null:
19585         81 7/subop/compare %edi 0/imm32
19586         0f 84/jump-if-= $mu-stmt-matches-primitive?:check-outputs/disp32
19587 $mu-stmt-matches-primitive?:stmt-inout-null-and-prim-inout-not-null:
19588         # return false
19589         b8/copy-to-eax 0/imm32/false
19590         e9/jump $mu-stmt-matches-primitive?:end/disp32
19591       }
19592       # if (curr2 == 0) return false
19593       {
19594 $mu-stmt-matches-primitive?:check-prim-inout-null:
19595         81 7/subop/compare %edi 0/imm32
19596         75/jump-if-!= break/disp8
19597 $mu-stmt-matches-primitive?:prim-inout-null:
19598         b8/copy-to-eax 0/imm32/false
19599         e9/jump $mu-stmt-matches-primitive?:end/disp32
19600       }
19601       # if (curr != curr2) return false
19602       {
19603 $mu-stmt-matches-primitive?:check-inouts-match:
19604         (lookup *edi *(edi+4))  # List-value List-value => eax
19605         (operand-matches-primitive? %esi %eax)  # => eax
19606         3d/compare-eax-and 0/imm32/false
19607         75/jump-if-!= break/disp8
19608 $mu-stmt-matches-primitive?:inouts-match:
19609         b8/copy-to-eax 0/imm32/false
19610         e9/jump $mu-stmt-matches-primitive?:end/disp32
19611       }
19612 $mu-stmt-matches-primitive?:next-inout:
19613       # curr = lookup(curr->next)
19614       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
19615       89/<- %esi 0/r32/eax
19616       # curr2 = lookup(curr2->next)
19617       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
19618       89/<- %edi 0/r32/eax
19619       #
19620       e9/jump loop/disp32
19621     }
19622 $mu-stmt-matches-primitive?:check-outputs:
19623     # var curr/esi: (addr stmt-var) = lookup(stmt->outputs)
19624     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
19625     89/<- %esi 0/r32/eax
19626     # var curr2/edi: (addr list var) = lookup(primitive->outputs)
19627     (lookup *(edx+0x10) *(edx+0x14))  # Primitive-outputs Primitive-outputs => eax
19628     89/<- %edi 0/r32/eax
19629     {
19630 $mu-stmt-matches-primitive?:outputs-loop:
19631       # if (curr == 0) return (curr2 == 0)
19632       {
19633 $mu-stmt-matches-primitive?:check-both-outputs-null:
19634         81 7/subop/compare %esi 0/imm32
19635         75/jump-if-!= break/disp8
19636         {
19637 $mu-stmt-matches-primitive?:stmt-output-null:
19638           81 7/subop/compare %edi 0/imm32
19639           75/jump-if-!= break/disp8
19640 $mu-stmt-matches-primitive?:both-outputs-null:
19641           # return true
19642           b8/copy-to-eax 1/imm32
19643           e9/jump $mu-stmt-matches-primitive?:end/disp32
19644         }
19645 $mu-stmt-matches-primitive?:stmt-output-null-and-prim-output-not-null:
19646         # return false
19647         b8/copy-to-eax 0/imm32
19648         e9/jump $mu-stmt-matches-primitive?:end/disp32
19649       }
19650       # if (curr2 == 0) return false
19651       {
19652 $mu-stmt-matches-primitive?:check-prim-output-null:
19653         81 7/subop/compare %edi 0/imm32
19654         75/jump-if-!= break/disp8
19655 $mu-stmt-matches-primitive?:prim-output-is-null:
19656         b8/copy-to-eax 0/imm32
19657         e9/jump $mu-stmt-matches-primitive?:end/disp32
19658       }
19659       # if (curr != curr2) return false
19660       {
19661 $mu-stmt-matches-primitive?:check-outputs-match:
19662         (lookup *edi *(edi+4))  # List-value List-value => eax
19663         (operand-matches-primitive? %esi %eax)  # => eax
19664         3d/compare-eax-and 0/imm32/false
19665         75/jump-if-!= break/disp8
19666 $mu-stmt-matches-primitive?:outputs-match:
19667         b8/copy-to-eax 0/imm32
19668         e9/jump $mu-stmt-matches-primitive?:end/disp32
19669       }
19670 $mu-stmt-matches-primitive?:next-output:
19671       # curr = lookup(curr->next)
19672       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
19673       89/<- %esi 0/r32/eax
19674       # curr2 = lookup(curr2->next)
19675       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
19676       89/<- %edi 0/r32/eax
19677       #
19678       e9/jump loop/disp32
19679     }
19680 $mu-stmt-matches-primitive?:return-true:
19681     b8/copy-to-eax 1/imm32
19682 $mu-stmt-matches-primitive?:end:
19683     # . restore registers
19684     5f/pop-to-edi
19685     5e/pop-to-esi
19686     5b/pop-to-ebx
19687     5a/pop-to-edx
19688     59/pop-to-ecx
19689     # . epilogue
19690     89/<- %esp 5/r32/ebp
19691     5d/pop-to-ebp
19692     c3/return
19693 
19694 operand-matches-primitive?:  # s: (addr stmt-var), prim-var: (addr var) -> result/eax: boolean
19695     # . prologue
19696     55/push-ebp
19697     89/<- %ebp 4/r32/esp
19698     # . save registers
19699     51/push-ecx
19700     52/push-edx
19701     53/push-ebx
19702     56/push-esi
19703     57/push-edi
19704     # ecx = s
19705     8b/-> *(ebp+8) 1/r32/ecx
19706     # var var/esi: (addr var) = lookup(s->value)
19707     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
19708     89/<- %esi 0/r32/eax
19709     # edi = prim-var
19710     8b/-> *(ebp+0xc) 7/r32/edi
19711 $operand-matches-primitive?:check-type:
19712     # if !category-match?(var->type, prim-var->type) return false
19713     # . var vtype/ebx: (addr type-tree) = lookup(var->type)
19714     (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
19715     89/<- %ebx 0/r32/eax
19716     # . var ptype/eax: (addr type-tree) = lookup(prim-var->type)
19717     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
19718     (subx-type-category-match? %ebx %eax)  # => eax
19719     3d/compare-eax-and 0/imm32/false
19720     0f 84/jump-if-= $operand-matches-primitive?:return-false/disp32
19721     {
19722 $operand-matches-primitive?:check-register:
19723       # if prim-var is in memory and var is in register but dereference, match
19724       {
19725         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
19726         0f 85/jump-if-!= break/disp32
19727         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
19728         74/jump-if-= break/disp8
19729         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
19730         74/jump-if-= break/disp8
19731 $operand-matches-primitive?:var-deref-match:
19732         e9/jump $operand-matches-primitive?:return-true/disp32
19733       }
19734       # if prim-var is in register and var is in register but dereference, no match
19735       {
19736         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
19737         0f 84/jump-if-= break/disp32
19738         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
19739         0f 84/jump-if-= break/disp32
19740         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
19741         74/jump-if-= break/disp8
19742 $operand-matches-primitive?:var-deref-no-match:
19743         e9/jump $operand-matches-primitive?:return-false/disp32
19744       }
19745       # return false if var->register doesn't match prim-var->register
19746       {
19747         # if register addresses are equal, it's a match
19748         # var vreg/ebx: (addr array byte) = lookup(var->register)
19749         (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
19750         89/<- %ebx 0/r32/eax
19751         # var preg/ecx: (addr array byte) = lookup(prim-var->register)
19752         (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
19753         89/<- %ecx 0/r32/eax
19754         # if (vreg == preg) break
19755         39/compare %ecx 3/r32/ebx
19756         74/jump-if-= break/disp8
19757 $operand-matches-primitive?:var-register-no-match:
19758         # if either address is 0, return false
19759         81 7/subop/compare %ebx 0/imm32
19760         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
19761         81 7/subop/compare %ecx 0/imm32
19762         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
19763         # if prim-var->register is wildcard, it's a match
19764         (string-equal? %ecx "*")  # Any-register => eax
19765         3d/compare-eax-and 0/imm32/false
19766         75/jump-if-!= break/disp8
19767 $operand-matches-primitive?:wildcard-no-match:
19768         # if string contents aren't equal, return false
19769         (string-equal? %ecx %ebx)  # => eax
19770         3d/compare-eax-and 0/imm32/false
19771         74/jump-if-= $operand-matches-primitive?:return-false/disp8
19772       }
19773     }
19774 $operand-matches-primitive?:return-true:
19775     b8/copy-to-eax 1/imm32/true
19776     eb/jump $operand-matches-primitive?:end/disp8
19777 $operand-matches-primitive?:return-false:
19778     b8/copy-to-eax 0/imm32/false
19779 $operand-matches-primitive?:end:
19780     # . restore registers
19781     5f/pop-to-edi
19782     5e/pop-to-esi
19783     5b/pop-to-ebx
19784     5a/pop-to-edx
19785     59/pop-to-ecx
19786     # . epilogue
19787     89/<- %esp 5/r32/ebp
19788     5d/pop-to-ebp
19789     c3/return
19790 
19791 find-matching-function:  # functions: (addr function), stmt: (addr stmt) -> result/eax: (addr function)
19792     # . prologue
19793     55/push-ebp
19794     89/<- %ebp 4/r32/esp
19795     # . save registers
19796     51/push-ecx
19797     # var curr/ecx: (handle function) = functions
19798     8b/-> *(ebp+8) 1/r32/ecx
19799     {
19800       # if (curr == null) break
19801       81 7/subop/compare %ecx 0/imm32
19802       74/jump-if-= break/disp8
19803 #?       (write-buffered Stderr "iter\n")
19804 #?       (flush Stderr)
19805       # if match(stmt, curr) return curr
19806       {
19807         (mu-stmt-matches-function? *(ebp+0xc) %ecx)  # => eax
19808         3d/compare-eax-and 0/imm32/false
19809         74/jump-if-= break/disp8
19810         89/<- %eax 1/r32/ecx
19811         eb/jump $find-matching-function:end/disp8
19812       }
19813       # curr = curr->next
19814       (lookup *(ecx+0x20) *(ecx+0x24))  # Function-next Function-next => eax
19815       89/<- %ecx 0/r32/eax
19816       #
19817       eb/jump loop/disp8
19818     }
19819     # return null
19820     b8/copy-to-eax 0/imm32
19821 $find-matching-function:end:
19822     # . restore registers
19823     59/pop-to-ecx
19824     # . epilogue
19825     89/<- %esp 5/r32/ebp
19826     5d/pop-to-ebp
19827     c3/return
19828 
19829 # Just compare names; user-defined functions don't support overloading yet.
19830 mu-stmt-matches-function?:  # stmt: (addr stmt1), function: (addr function) -> result/eax: boolean
19831     # . prologue
19832     55/push-ebp
19833     89/<- %ebp 4/r32/esp
19834     # . save registers
19835     51/push-ecx
19836     # return function->name == stmt->operation
19837     # ecx = lookup(stmt->operation)
19838     8b/-> *(ebp+8) 0/r32/eax
19839     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
19840     89/<- %ecx 0/r32/eax
19841     # eax = lookup(function->name)
19842     8b/-> *(ebp+0xc) 0/r32/eax
19843     (lookup *eax *(eax+4))  # Function-name Function-name => eax
19844     (string-equal? %eax %ecx)  # => eax
19845 $mu-stmt-matches-function?:end:
19846     # . restore registers
19847     59/pop-to-ecx
19848     # . epilogue
19849     89/<- %esp 5/r32/ebp
19850     5d/pop-to-ebp
19851     c3/return
19852 
19853 # Type-checking happens elsewhere. This method is for selecting between
19854 # primitives.
19855 subx-type-category-match?:  # a: (addr type-tree), b: (addr type-tree) -> result/eax: boolean
19856     # . prologue
19857     55/push-ebp
19858     89/<- %ebp 4/r32/esp
19859     # . save registers
19860     51/push-ecx
19861     # var alit/ecx: boolean = is-literal-type?(a)
19862     (is-simple-mu-type? *(ebp+8) 0)  # => eax
19863     89/<- %ecx 0/r32/eax
19864     # var blit/eax: boolean = is-literal-type?(b)
19865     (is-simple-mu-type? *(ebp+0xc) 0)  # => eax
19866     # return alit == blit
19867     39/compare %eax 1/r32/ecx
19868     0f 94/set-byte-if-= %al
19869     81 4/subop/and %eax 0xff/imm32
19870 $subx-type-category-match?:end:
19871     # . restore registers
19872     59/pop-to-ecx
19873     # . epilogue
19874     89/<- %esp 5/r32/ebp
19875     5d/pop-to-ebp
19876     c3/return
19877 
19878 is-simple-mu-type?:  # a: (addr type-tree), n: type-id -> result/eax: boolean
19879     # . prologue
19880     55/push-ebp
19881     89/<- %ebp 4/r32/esp
19882     # . save registers
19883     51/push-ecx
19884     # ecx = n
19885     8b/-> *(ebp+0xc) 1/r32/ecx
19886     # return (a->value == n)
19887     8b/-> *(ebp+8) 0/r32/eax
19888     39/compare *(eax+4) 1/r32/ecx  # Type-tree-value
19889     0f 94/set-byte-if-= %al
19890     81 4/subop/and %eax 0xff/imm32
19891 $is-simple-mu-type?:end:
19892     # . restore registers
19893     59/pop-to-ecx
19894     # . epilogue
19895     89/<- %esp 5/r32/ebp
19896     5d/pop-to-ebp
19897     c3/return
19898 
19899 is-mu-addr-type?:  # a: (addr type-tree) -> result/eax: boolean
19900     # . prologue
19901     55/push-ebp
19902     89/<- %ebp 4/r32/esp
19903     # eax = a
19904     8b/-> *(ebp+8) 0/r32/eax
19905     # if (!a->is-atom?) a = a->left
19906     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
19907     {
19908       75/jump-if-!= break/disp8
19909       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
19910     }
19911     # return (a->value == addr)
19912     81 7/subop/compare *(eax+4) 2/imm32/addr  # Type-tree-value
19913     0f 94/set-byte-if-= %al
19914     81 4/subop/and %eax 0xff/imm32
19915 $is-mu-addr-type?:end:
19916     # . epilogue
19917     89/<- %esp 5/r32/ebp
19918     5d/pop-to-ebp
19919     c3/return
19920 
19921 is-mu-array-type?:  # a: (addr type-tree) -> result/eax: boolean
19922     # . prologue
19923     55/push-ebp
19924     89/<- %ebp 4/r32/esp
19925     # eax = a
19926     8b/-> *(ebp+8) 0/r32/eax
19927     # if (!a->is-atom?) a = a->left
19928     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
19929     {
19930       75/jump-if-!= break/disp8
19931       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
19932     }
19933     # return (a->value == array)
19934     81 7/subop/compare *(eax+4) 3/imm32/array  # Type-tree-value
19935     0f 94/set-byte-if-= %al
19936     81 4/subop/and %eax 0xff/imm32
19937 $is-mu-array-type?:end:
19938     # . epilogue
19939     89/<- %esp 5/r32/ebp
19940     5d/pop-to-ebp
19941     c3/return
19942 
19943 is-mu-stream-type?:  # a: (addr type-tree) -> result/eax: boolean
19944     # . prologue
19945     55/push-ebp
19946     89/<- %ebp 4/r32/esp
19947     # eax = a
19948     8b/-> *(ebp+8) 0/r32/eax
19949     # if (!a->is-atom?) a = a->left
19950     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
19951     {
19952       75/jump-if-!= break/disp8
19953       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
19954     }
19955     # return (a->value == stream)
19956     81 7/subop/compare *(eax+4) 0xb/imm32/stream  # Type-tree-value
19957     0f 94/set-byte-if-= %al
19958     81 4/subop/and %eax 0xff/imm32
19959 $is-mu-stream-type?:end:
19960     # . epilogue
19961     89/<- %esp 5/r32/ebp
19962     5d/pop-to-ebp
19963     c3/return
19964 
19965 test-emit-subx-stmt-primitive:
19966     # Primitive operation on a variable on the stack.
19967     #   increment foo
19968     # =>
19969     #   ff 0/subop/increment *(ebp-8)
19970     #
19971     # There's a variable on the var stack as follows:
19972     #   name: 'foo'
19973     #   type: int
19974     #   stack-offset: -8
19975     #
19976     # There's a primitive with this info:
19977     #   name: 'increment'
19978     #   inouts: int/mem
19979     #   value: 'ff 0/subop/increment'
19980     #
19981     # . prologue
19982     55/push-ebp
19983     89/<- %ebp 4/r32/esp
19984     # setup
19985     (clear-stream _test-output-stream)
19986     (clear-stream $_test-output-buffered-file->buffer)
19987     # simulate allocated payloads starting with an initial fake alloc-id (0x11)
19988 $test-emit-subx-stmt-primitive:initialize-type:
19989     # var type/ecx: (payload type-tree) = int
19990     68/push 0/imm32/right:null
19991     68/push 0/imm32/right:null
19992     68/push 0/imm32/left:unused
19993     68/push 1/imm32/value:int
19994     68/push 1/imm32/is-atom?:true
19995     68/push 0x11/imm32/alloc-id:fake:payload
19996     89/<- %ecx 4/r32/esp
19997 $test-emit-subx-stmt-primitive:initialize-var:
19998     # var var-foo/ecx: (payload var) = var(type)
19999     68/push 0/imm32/no-register
20000     68/push 0/imm32/no-register
20001     68/push -8/imm32/stack-offset
20002     68/push 1/imm32/block-depth
20003     51/push-ecx/type
20004     68/push 0x11/imm32/alloc-id:fake
20005     68/push 0/imm32/name
20006     68/push 0/imm32/name
20007     68/push 0x11/imm32/alloc-id:fake:payload
20008     89/<- %ecx 4/r32/esp
20009 $test-emit-subx-stmt-primitive:initialize-var-name:
20010     # var-foo->name = "foo"
20011     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20012     (copy-array Heap "foo" %eax)
20013 $test-emit-subx-stmt-primitive:initialize-stmt-var:
20014     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
20015     68/push 0/imm32/is-deref:false
20016     68/push 0/imm32/next
20017     68/push 0/imm32/next
20018     51/push-ecx/var-foo
20019     68/push 0x11/imm32/alloc-id:fake
20020     68/push 0x11/imm32/alloc-id:fake:payload
20021     89/<- %ebx 4/r32/esp
20022 $test-emit-subx-stmt-primitive:initialize-stmt:
20023     # var stmt/esi: (addr statement)
20024     68/push 0/imm32/no-outputs
20025     68/push 0/imm32/no-outputs
20026     53/push-ebx/inouts
20027     68/push 0x11/imm32/alloc-id:fake
20028     68/push 0/imm32/operation
20029     68/push 0/imm32/operation
20030     68/push 1/imm32/tag
20031     89/<- %esi 4/r32/esp
20032 $test-emit-subx-stmt-primitive:initialize-stmt-operation:
20033     # stmt->operation = "increment"
20034     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20035     (copy-array Heap "increment" %eax)
20036 $test-emit-subx-stmt-primitive:initialize-primitive:
20037     # var primitives/ebx: (addr primitive)
20038     68/push 0/imm32/next
20039     68/push 0/imm32/next
20040     68/push 0/imm32/output-is-write-only
20041     68/push 0/imm32/no-disp32
20042     68/push 0/imm32/no-imm8
20043     68/push 0/imm32/no-imm32
20044     68/push 0/imm32/no-r32
20045     68/push 1/imm32/rm32-is-first-inout
20046     68/push 0/imm32/subx-name
20047     68/push 0/imm32/subx-name
20048     68/push 0/imm32/no-outputs
20049     68/push 0/imm32/no-outputs
20050     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
20051     68/push 0x11/imm32/alloc-id:fake
20052     68/push 0/imm32/name
20053     68/push 0/imm32/name
20054     89/<- %ebx 4/r32/esp
20055 $test-emit-subx-stmt-primitive:initialize-primitive-name:
20056     # primitives->name = "increment"
20057     (copy-array Heap "increment" %ebx)  # Primitive-name
20058 $test-emit-subx-stmt-primitive:initialize-primitive-subx-name:
20059     # primitives->subx-name = "ff 0/subop/increment"
20060     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
20061     (copy-array Heap "ff 0/subop/increment" %eax)
20062     # convert
20063     c7 0/subop/copy *Curr-block-depth 0/imm32
20064     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
20065     (flush _test-output-buffered-file)
20066 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20072     # check output
20073     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-stmt-primitive")
20074     # . epilogue
20075     89/<- %esp 5/r32/ebp
20076     5d/pop-to-ebp
20077     c3/return
20078 
20079 test-emit-subx-stmt-primitive-register:
20080     # Primitive operation on a variable in a register.
20081     #   foo <- increment
20082     # =>
20083     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
20084     #
20085     # There's a variable on the var stack as follows:
20086     #   name: 'foo'
20087     #   type: int
20088     #   register: 'eax'
20089     #
20090     # There's a primitive with this info:
20091     #   name: 'increment'
20092     #   out: int/reg
20093     #   value: 'ff 0/subop/increment'
20094     #
20095     # . prologue
20096     55/push-ebp
20097     89/<- %ebp 4/r32/esp
20098     # setup
20099     (clear-stream _test-output-stream)
20100     (clear-stream $_test-output-buffered-file->buffer)
20101 $test-emit-subx-stmt-primitive-register:initialize-type:
20102     # var type/ecx: (payload type-tree) = int
20103     68/push 0/imm32/right:null
20104     68/push 0/imm32/right:null
20105     68/push 0/imm32/left:unused
20106     68/push 1/imm32/value:int
20107     68/push 1/imm32/is-atom?:true
20108     68/push 0x11/imm32/alloc-id:fake:payload
20109     89/<- %ecx 4/r32/esp
20110 $test-emit-subx-stmt-primitive-register:initialize-var:
20111     # var var-foo/ecx: (payload var)
20112     68/push 0/imm32/register
20113     68/push 0/imm32/register
20114     68/push 0/imm32/no-stack-offset
20115     68/push 1/imm32/block-depth
20116     51/push-ecx
20117     68/push 0x11/imm32/alloc-id:fake
20118     68/push 0/imm32/name
20119     68/push 0/imm32/name
20120     68/push 0x11/imm32/alloc-id:fake:payload
20121     89/<- %ecx 4/r32/esp
20122 $test-emit-subx-stmt-primitive-register:initialize-var-name:
20123     # var-foo->name = "foo"
20124     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20125     (copy-array Heap "foo" %eax)
20126 $test-emit-subx-stmt-primitive-register:initialize-var-register:
20127     # var-foo->register = "eax"
20128     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
20129     (copy-array Heap "eax" %eax)
20130 $test-emit-subx-stmt-primitive-register:initialize-stmt-var:
20131     # var operand/ebx: (payload stmt-var)
20132     68/push 0/imm32/is-deref:false
20133     68/push 0/imm32/next
20134     68/push 0/imm32/next
20135     51/push-ecx/var-foo
20136     68/push 0x11/imm32/alloc-id:fake
20137     68/push 0x11/imm32/alloc-id:fake:payload
20138     89/<- %ebx 4/r32/esp
20139 $test-emit-subx-stmt-primitive-register:initialize-stmt:
20140     # var stmt/esi: (addr statement)
20141     53/push-ebx/outputs
20142     68/push 0x11/imm32/alloc-id:fake
20143     68/push 0/imm32/no-inouts
20144     68/push 0/imm32/no-inouts
20145     68/push 0/imm32/operation
20146     68/push 0/imm32/operation
20147     68/push 1/imm32
20148     89/<- %esi 4/r32/esp
20149 $test-emit-subx-stmt-primitive-register:initialize-stmt-operation:
20150     # stmt->operation = "increment"
20151     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20152     (copy-array Heap "increment" %eax)
20153 $test-emit-subx-stmt-primitive-register:initialize-formal-var:
20154     # var formal-var/ebx: (payload var)
20155     68/push 0/imm32/register
20156     68/push 0/imm32/register
20157     68/push 0/imm32/no-stack-offset
20158     68/push 1/imm32/block-depth
20159     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
20160     68/push 0x11/imm32/alloc-id:fake
20161     68/push 0/imm32/name
20162     68/push 0/imm32/name
20163     68/push 0x11/imm32/alloc-id:fake:payload
20164     89/<- %ebx 4/r32/esp
20165 $test-emit-subx-stmt-primitive-register:initialize-formal-var-name:
20166     # formal-var->name = "dummy"
20167     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
20168     (copy-array Heap "dummy" %eax)
20169 $test-emit-subx-stmt-primitive-register:initialize-formal-register:
20170     # formal-var->register = "*"
20171     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
20172     (copy-array Heap "*" %eax)  # Any-register
20173 $test-emit-subx-stmt-primitive-register:initialize-var-list:
20174     # var formal-outputs/ebx: (payload list var)
20175     68/push 0/imm32/next
20176     68/push 0/imm32/next
20177     53/push-ebx/formal-var
20178     68/push 0x11/imm32/alloc-id:fake
20179     68/push 0x11/imm32/alloc-id:fake:payload
20180     89/<- %ebx 4/r32/esp
20181 $test-emit-subx-stmt-primitive-register:initialize-primitive:
20182     # var primitives/ebx: (addr primitive)
20183     68/push 0/imm32/next
20184     68/push 0/imm32/next
20185     68/push 0/imm32/output-is-write-only
20186     68/push 0/imm32/no-disp32
20187     68/push 0/imm32/no-imm8
20188     68/push 0/imm32/no-imm32
20189     68/push 0/imm32/no-r32
20190     68/push 3/imm32/rm32-is-first-output
20191     68/push 0/imm32/subx-name
20192     68/push 0/imm32/subx-name
20193     53/push-ebx/outputs
20194     68/push 0x11/imm32/alloc-id:fake
20195     68/push 0/imm32/no-inouts
20196     68/push 0/imm32/no-inouts
20197     68/push 0/imm32/name
20198     68/push 0/imm32/name
20199     89/<- %ebx 4/r32/esp
20200 $test-emit-subx-stmt-primitive-register:initialize-primitive-name:
20201     # primitives->name = "increment"
20202     (copy-array Heap "increment" %ebx)  # Primitive-name
20203 $test-emit-subx-stmt-primitive-register:initialize-primitive-subx-name:
20204     # primitives->subx-name = "ff 0/subop/increment"
20205     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
20206     (copy-array Heap "ff 0/subop/increment" %eax)
20207     # convert
20208     c7 0/subop/copy *Curr-block-depth 0/imm32
20209     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
20210     (flush _test-output-buffered-file)
20211 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20217     # check output
20218     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-primitive-register")
20219     # . epilogue
20220     89/<- %esp 5/r32/ebp
20221     5d/pop-to-ebp
20222     c3/return
20223 
20224 test-emit-subx-stmt-select-primitive:
20225     # Select the right primitive between overloads.
20226     #   foo <- increment
20227     # =>
20228     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
20229     #
20230     # There's a variable on the var stack as follows:
20231     #   name: 'foo'
20232     #   type: int
20233     #   register: 'eax'
20234     #
20235     # There's two primitives, as follows:
20236     #   - name: 'increment'
20237     #     out: int/reg
20238     #     value: 'ff 0/subop/increment'
20239     #   - name: 'increment'
20240     #     inout: int/mem
20241     #     value: 'ff 0/subop/increment'
20242     #
20243     # . prologue
20244     55/push-ebp
20245     89/<- %ebp 4/r32/esp
20246     # setup
20247     (clear-stream _test-output-stream)
20248     (clear-stream $_test-output-buffered-file->buffer)
20249 $test-emit-subx-stmt-select-primitive:initialize-type:
20250     # var type/ecx: (payload type-tree) = int
20251     68/push 0/imm32/right:null
20252     68/push 0/imm32/right:null
20253     68/push 0/imm32/left:unused
20254     68/push 1/imm32/value:int
20255     68/push 1/imm32/is-atom?:true
20256     68/push 0x11/imm32/alloc-id:fake:payload
20257     89/<- %ecx 4/r32/esp
20258 $test-emit-subx-stmt-select-primitive:initialize-var:
20259     # var var-foo/ecx: (payload var)
20260     68/push 0/imm32/register
20261     68/push 0/imm32/register
20262     68/push 0/imm32/no-stack-offset
20263     68/push 1/imm32/block-depth
20264     51/push-ecx
20265     68/push 0x11/imm32/alloc-id:fake
20266     68/push 0/imm32/name
20267     68/push 0/imm32/name
20268     68/push 0x11/imm32/alloc-id:fake:payload
20269     89/<- %ecx 4/r32/esp
20270 $test-emit-subx-stmt-select-primitive:initialize-var-name:
20271     # var-foo->name = "foo"
20272     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20273     (copy-array Heap "foo" %eax)
20274 $test-emit-subx-stmt-select-primitive:initialize-var-register:
20275     # var-foo->register = "eax"
20276     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
20277     (copy-array Heap "eax" %eax)
20278 $test-emit-subx-stmt-select-primitive:initialize-stmt-var:
20279     # var operand/ebx: (payload stmt-var)
20280     68/push 0/imm32/is-deref:false
20281     68/push 0/imm32/next
20282     68/push 0/imm32/next
20283     51/push-ecx/var-foo
20284     68/push 0x11/imm32/alloc-id:fake
20285     68/push 0x11/imm32/alloc-id:fake:payload
20286     89/<- %ebx 4/r32/esp
20287 $test-emit-subx-stmt-select-primitive:initialize-stmt:
20288     # var stmt/esi: (addr statement)
20289     53/push-ebx/outputs
20290     68/push 0x11/imm32/alloc-id:fake
20291     68/push 0/imm32/no-inouts
20292     68/push 0/imm32/no-inouts
20293     68/push 0/imm32/operation
20294     68/push 0/imm32/operation
20295     68/push 1/imm32
20296     89/<- %esi 4/r32/esp
20297 $test-emit-subx-stmt-select-primitive:initialize-stmt-operation:
20298     # stmt->operation = "increment"
20299     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20300     (copy-array Heap "increment" %eax)
20301 $test-emit-subx-stmt-select-primitive:initialize-formal-var:
20302     # var formal-var/ebx: (payload var)
20303     68/push 0/imm32/register
20304     68/push 0/imm32/register
20305     68/push 0/imm32/no-stack-offset
20306     68/push 1/imm32/block-depth
20307     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
20308     68/push 0x11/imm32/alloc-id:fake
20309     68/push 0/imm32/name
20310     68/push 0/imm32/name
20311     68/push 0x11/imm32/alloc-id:fake:payload
20312     89/<- %ebx 4/r32/esp
20313 $test-emit-subx-stmt-select-primitive:initialize-formal-var-name:
20314     # formal-var->name = "dummy"
20315     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
20316     (copy-array Heap "dummy" %eax)
20317 $test-emit-subx-stmt-select-primitive:initialize-formal-register:
20318     # formal-var->register = "*"
20319     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
20320     (copy-array Heap "*" %eax)  # Any-register
20321 $test-emit-subx-stmt-select-primitive:initialize-var-list:
20322     # var formal-outputs/ebx: (payload list var)
20323     68/push 0/imm32/next
20324     68/push 0/imm32/next
20325     53/push-ebx/formal-var
20326     68/push 0x11/imm32/alloc-id:fake
20327     68/push 0x11/imm32/alloc-id:fake:payload
20328     89/<- %ebx 4/r32/esp
20329 $test-emit-subx-stmt-select-primitive:initialize-primitive2:
20330     # var primitive2/edi: (payload primitive)
20331     68/push 0/imm32/next
20332     68/push 0/imm32/next
20333     68/push 0/imm32/output-is-write-only
20334     68/push 0/imm32/no-disp32
20335     68/push 0/imm32/no-imm8
20336     68/push 0/imm32/no-imm32
20337     68/push 0/imm32/no-r32
20338     68/push 3/imm32/rm32-is-first-output
20339     68/push 0/imm32/subx-name
20340     68/push 0/imm32/subx-name
20341     53/push-ebx/outputs
20342     68/push 0x11/imm32/alloc-id:fake
20343     68/push 0/imm32/no-inouts
20344     68/push 0/imm32/no-inouts
20345     68/push 0/imm32/name
20346     68/push 0/imm32/name
20347     68/push 0x11/imm32/alloc-id:fake:payload
20348     89/<- %edi 4/r32/esp
20349 $test-emit-subx-stmt-select-primitive:initialize-primitive2-name:
20350     # primitives->name = "increment"
20351     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
20352     (copy-array Heap "increment" %eax)
20353 $test-emit-subx-stmt-select-primitive:initialize-primitive2-subx-name:
20354     # primitives->subx-name = "ff 0/subop/increment"
20355     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
20356     (copy-array Heap "ff 0/subop/increment" %eax)
20357 $test-emit-subx-stmt-select-primitive:initialize-primitive:
20358     # var primitives/ebx: (addr primitive)
20359     57/push-edi
20360     68/push 0x11/imm32/alloc-id:fake
20361     68/push 0/imm32/output-is-write-only
20362     68/push 0/imm32/no-disp32
20363     68/push 0/imm32/no-imm8
20364     68/push 0/imm32/no-imm32
20365     68/push 0/imm32/no-r32
20366     68/push 1/imm32/rm32-is-first-inout
20367     68/push 0/imm32/subx-name
20368     68/push 0/imm32/subx-name
20369     68/push 0/imm32/no-outputs
20370     68/push 0/imm32/no-outputs
20371     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
20372     68/push 0x11/imm32/alloc-id:fake
20373     68/push 0/imm32/name
20374     68/push 0/imm32/name
20375     89/<- %ebx 4/r32/esp
20376 $test-emit-subx-stmt-select-primitive:initialize-primitive-name:
20377     # primitives->name = "increment"
20378     (copy-array Heap "increment" %ebx)  # Primitive-name
20379 $test-emit-subx-stmt-select-primitive:initialize-primitive-subx-name:
20380     # primitives->subx-name = "ff 0/subop/increment"
20381     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
20382     (copy-array Heap "ff 0/subop/increment" %eax)
20383     # convert
20384     c7 0/subop/copy *Curr-block-depth 0/imm32
20385     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
20386     (flush _test-output-buffered-file)
20387 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20393     # check output
20394     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive")
20395     # . epilogue
20396     89/<- %esp 5/r32/ebp
20397     5d/pop-to-ebp
20398     c3/return
20399 
20400 test-emit-subx-stmt-select-primitive-2:
20401     # Select the right primitive between overloads.
20402     #   increment foo
20403     # =>
20404     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
20405     #
20406     # There's a variable on the var stack as follows:
20407     #   name: 'foo'
20408     #   type: int
20409     #   register: 'eax'
20410     #
20411     # There's two primitives, as follows:
20412     #   - name: 'increment'
20413     #     out: int/reg
20414     #     value: 'ff 0/subop/increment'
20415     #   - name: 'increment'
20416     #     inout: int/mem
20417     #     value: 'ff 0/subop/increment'
20418     #
20419     # . prologue
20420     55/push-ebp
20421     89/<- %ebp 4/r32/esp
20422     # setup
20423     (clear-stream _test-output-stream)
20424     (clear-stream $_test-output-buffered-file->buffer)
20425 $test-emit-subx-stmt-select-primitive-2:initialize-type:
20426     # var type/ecx: (payload type-tree) = int
20427     68/push 0/imm32/right:null
20428     68/push 0/imm32/right:null
20429     68/push 0/imm32/left:unused
20430     68/push 1/imm32/value:int
20431     68/push 1/imm32/is-atom?:true
20432     68/push 0x11/imm32/alloc-id:fake:payload
20433     89/<- %ecx 4/r32/esp
20434 $test-emit-subx-stmt-select-primitive-2:initialize-var:
20435     # var var-foo/ecx: (payload var)
20436     68/push 0/imm32/register
20437     68/push 0/imm32/register
20438     68/push 0/imm32/no-stack-offset
20439     68/push 1/imm32/block-depth
20440     51/push-ecx
20441     68/push 0x11/imm32/alloc-id:fake
20442     68/push 0/imm32/name
20443     68/push 0/imm32/name
20444     68/push 0x11/imm32/alloc-id:fake:payload
20445     89/<- %ecx 4/r32/esp
20446 $test-emit-subx-stmt-select-primitive-2:initialize-var-name:
20447     # var-foo->name = "foo"
20448     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20449     (copy-array Heap "foo" %eax)
20450 $test-emit-subx-stmt-select-primitive-2:initialize-var-register:
20451     # var-foo->register = "eax"
20452     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
20453     (copy-array Heap "eax" %eax)
20454 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-var:
20455     # var operand/ebx: (payload stmt-var)
20456     68/push 0/imm32/is-deref:false
20457     68/push 0/imm32/next
20458     68/push 0/imm32/next
20459     51/push-ecx/var-foo
20460     68/push 0x11/imm32/alloc-id:fake
20461     68/push 0x11/imm32/alloc-id:fake:payload
20462     89/<- %ebx 4/r32/esp
20463 $test-emit-subx-stmt-select-primitive-2:initialize-stmt:
20464     # var stmt/esi: (addr statement)
20465     68/push 0/imm32/no-outputs
20466     68/push 0/imm32/no-outputs
20467     53/push-ebx/inouts
20468     68/push 0x11/imm32/alloc-id:fake
20469     68/push 0/imm32/operation
20470     68/push 0/imm32/operation
20471     68/push 1/imm32
20472     89/<- %esi 4/r32/esp
20473 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-operation:
20474     # stmt->operation = "increment"
20475     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20476     (copy-array Heap "increment" %eax)
20477 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var:
20478     # var formal-var/ebx: (payload var)
20479     68/push 0/imm32/register
20480     68/push 0/imm32/register
20481     68/push 0/imm32/no-stack-offset
20482     68/push 1/imm32/block-depth
20483     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
20484     68/push 0x11/imm32/alloc-id:fake
20485     68/push 0/imm32/name
20486     68/push 0/imm32/name
20487     68/push 0x11/imm32/alloc-id:fake:payload
20488     89/<- %ebx 4/r32/esp
20489 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var-name:
20490     # formal-var->name = "dummy"
20491     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
20492     (copy-array Heap "dummy" %eax)
20493 $test-emit-subx-stmt-select-primitive-2:initialize-formal-register:
20494     # formal-var->register = "*"
20495     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
20496     (copy-array Heap "*" %eax)  # Any-register
20497 $test-emit-subx-stmt-select-primitive-2:initialize-var-list:
20498     # var formal-outputs/ebx: (payload list stmt-var)
20499     68/push 0/imm32/next
20500     68/push 0/imm32/next
20501     53/push-ebx/formal-var
20502     68/push 0x11/imm32/alloc-id:fake
20503     68/push 0x11/imm32/alloc-id:fake:payload
20504     89/<- %ebx 4/r32/esp
20505 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2:
20506     # var primitive2/edi: (payload primitive)
20507     68/push 0/imm32/next
20508     68/push 0/imm32/next
20509     68/push 0/imm32/output-is-write-only
20510     68/push 0/imm32/no-disp32
20511     68/push 0/imm32/no-imm8
20512     68/push 0/imm32/no-imm32
20513     68/push 0/imm32/no-r32
20514     68/push 3/imm32/rm32-is-first-output
20515     68/push 0/imm32/subx-name
20516     68/push 0/imm32/subx-name
20517     53/push-ebx/outputs
20518     68/push 0x11/imm32/alloc-id:fake
20519     68/push 0/imm32/no-inouts
20520     68/push 0/imm32/no-inouts
20521     68/push 0/imm32/name
20522     68/push 0/imm32/name
20523     68/push 0x11/imm32/alloc-id:fake:payload
20524     89/<- %edi 4/r32/esp
20525 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-name:
20526     # primitives->name = "increment"
20527     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
20528     (copy-array Heap "increment" %eax)
20529 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-subx-name:
20530     # primitives->subx-name = "ff 0/subop/increment"
20531     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
20532     (copy-array Heap "ff 0/subop/increment" %eax)
20533 $test-emit-subx-stmt-select-primitive-2:initialize-primitive:
20534     # var primitives/ebx: (addr primitive)
20535     57/push-edi
20536     68/push 0x11/imm32/alloc-id:fake
20537     68/push 0/imm32/output-is-write-only
20538     68/push 0/imm32/no-disp32
20539     68/push 0/imm32/no-imm8
20540     68/push 0/imm32/no-imm32
20541     68/push 0/imm32/no-r32
20542     68/push 1/imm32/rm32-is-first-inout
20543     68/push 0/imm32/subx-name
20544     68/push 0/imm32/subx-name
20545     68/push 0/imm32/no-outputs
20546     68/push 0/imm32/no-outputs
20547     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
20548     68/push 0x11/imm32/alloc-id:fake
20549     68/push 0/imm32/name
20550     68/push 0/imm32/name
20551     89/<- %ebx 4/r32/esp
20552 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-name:
20553     # primitives->name = "increment"
20554     (copy-array Heap "increment" %ebx)  # Primitive-name
20555 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-subx-name:
20556     # primitives->subx-name = "ff 0/subop/increment"
20557     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
20558     (copy-array Heap "ff 0/subop/increment" %eax)
20559     # convert
20560     c7 0/subop/copy *Curr-block-depth 0/imm32
20561     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
20562     (flush _test-output-buffered-file)
20563 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20569     # check output
20570     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive-2")
20571     # . epilogue
20572     89/<- %esp 5/r32/ebp
20573     5d/pop-to-ebp
20574     c3/return
20575 
20576 test-increment-register:
20577     # Select the right register between overloads.
20578     #   foo <- increment
20579     # =>
20580     #   50/increment-eax
20581     #
20582     # There's a variable on the var stack as follows:
20583     #   name: 'foo'
20584     #   type: int
20585     #   register: 'eax'
20586     #
20587     # Primitives are the global definitions.
20588     #
20589     # . prologue
20590     55/push-ebp
20591     89/<- %ebp 4/r32/esp
20592     # setup
20593     (clear-stream _test-output-stream)
20594     (clear-stream $_test-output-buffered-file->buffer)
20595 $test-increment-register:initialize-type:
20596     # var type/ecx: (payload type-tree) = int
20597     68/push 0/imm32/right:null
20598     68/push 0/imm32/right:null
20599     68/push 0/imm32/left:unused
20600     68/push 1/imm32/value:int
20601     68/push 1/imm32/is-atom?:true
20602     68/push 0x11/imm32/alloc-id:fake:payload
20603     89/<- %ecx 4/r32/esp
20604 $test-increment-register:initialize-var:
20605     # var var-foo/ecx: (payload var)
20606     68/push 0/imm32/register
20607     68/push 0/imm32/register
20608     68/push 0/imm32/no-stack-offset
20609     68/push 1/imm32/block-depth
20610     51/push-ecx
20611     68/push 0x11/imm32/alloc-id:fake
20612     68/push 0/imm32/name
20613     68/push 0/imm32/name
20614     68/push 0x11/imm32/alloc-id:fake:payload
20615     89/<- %ecx 4/r32/esp
20616 $test-increment-register:initialize-var-name:
20617     # var-foo->name = "foo"
20618     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20619     (copy-array Heap "foo" %eax)
20620 $test-increment-register:initialize-var-register:
20621     # var-foo->register = "eax"
20622     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
20623     (copy-array Heap "eax" %eax)
20624 $test-increment-register:initialize-stmt-var:
20625     # var operand/ebx: (payload stmt-var)
20626     68/push 0/imm32/is-deref:false
20627     68/push 0/imm32/next
20628     68/push 0/imm32/next
20629     51/push-ecx/var-foo
20630     68/push 0x11/imm32/alloc-id:fake
20631     68/push 0x11/imm32/alloc-id:fake:payload
20632     89/<- %ebx 4/r32/esp
20633 $test-increment-register:initialize-stmt:
20634     # var stmt/esi: (addr statement)
20635     53/push-ebx/outputs
20636     68/push 0x11/imm32/alloc-id:fake
20637     68/push 0/imm32/no-inouts
20638     68/push 0/imm32/no-inouts
20639     68/push 0/imm32/operation
20640     68/push 0/imm32/operation
20641     68/push 1/imm32
20642     89/<- %esi 4/r32/esp
20643 $test-increment-register:initialize-stmt-operation:
20644     # stmt->operation = "increment"
20645     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20646     (copy-array Heap "increment" %eax)
20647     # convert
20648     c7 0/subop/copy *Curr-block-depth 0/imm32
20649     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
20650     (flush _test-output-buffered-file)
20651 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20657     # check output
20658     (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register")
20659     # . epilogue
20660     89/<- %esp 5/r32/ebp
20661     5d/pop-to-ebp
20662     c3/return
20663 
20664 test-add-reg-to-reg:
20665     #   var1/reg <- add var2/reg
20666     # =>
20667     #   01/add-to %var1 var2
20668     #
20669     # . prologue
20670     55/push-ebp
20671     89/<- %ebp 4/r32/esp
20672     # setup
20673     (clear-stream _test-output-stream)
20674     (clear-stream $_test-output-buffered-file->buffer)
20675 $test-add-reg-to-reg:initialize-type:
20676     # var type/ecx: (payload type-tree) = int
20677     68/push 0/imm32/right:null
20678     68/push 0/imm32/right:null
20679     68/push 0/imm32/left:unused
20680     68/push 1/imm32/value:int
20681     68/push 1/imm32/is-atom?:true
20682     68/push 0x11/imm32/alloc-id:fake:payload
20683     89/<- %ecx 4/r32/esp
20684 $test-add-reg-to-reg:initialize-var1:
20685     # var var1/ecx: (payload var)
20686     68/push 0/imm32/register
20687     68/push 0/imm32/register
20688     68/push 0/imm32/no-stack-offset
20689     68/push 1/imm32/block-depth
20690     51/push-ecx
20691     68/push 0x11/imm32/alloc-id:fake
20692     68/push 0/imm32/name
20693     68/push 0/imm32/name
20694     68/push 0x11/imm32/alloc-id:fake:payload
20695     89/<- %ecx 4/r32/esp
20696 $test-add-reg-to-reg:initialize-var1-name:
20697     # var1->name = "var1"
20698     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20699     (copy-array Heap "var1" %eax)
20700 $test-add-reg-to-reg:initialize-var1-register:
20701     # var1->register = "eax"
20702     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
20703     (copy-array Heap "eax" %eax)
20704 $test-add-reg-to-reg:initialize-var2:
20705     # var var2/edx: (payload var)
20706     68/push 0/imm32/register
20707     68/push 0/imm32/register
20708     68/push 0/imm32/no-stack-offset
20709     68/push 1/imm32/block-depth
20710     ff 6/subop/push *(ecx+0x10)
20711     68/push 0x11/imm32/alloc-id:fake
20712     68/push 0/imm32/name
20713     68/push 0/imm32/name
20714     68/push 0x11/imm32/alloc-id:fake:payload
20715     89/<- %edx 4/r32/esp
20716 $test-add-reg-to-reg:initialize-var2-name:
20717     # var2->name = "var2"
20718     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
20719     (copy-array Heap "var2" %eax)
20720 $test-add-reg-to-reg:initialize-var2-register:
20721     # var2->register = "ecx"
20722     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
20723     (copy-array Heap "ecx" %eax)
20724 $test-add-reg-to-reg:initialize-inouts:
20725     # var inouts/esi: (payload stmt-var) = [var2]
20726     68/push 0/imm32/is-deref:false
20727     68/push 0/imm32/next
20728     68/push 0/imm32/next
20729     52/push-edx/var2
20730     68/push 0x11/imm32/alloc-id:fake
20731     68/push 0x11/imm32/alloc-id:fake:payload
20732     89/<- %esi 4/r32/esp
20733 $test-add-reg-to-reg:initialize-outputs:
20734     # var outputs/edi: (payload stmt-var) = [var1]
20735     68/push 0/imm32/is-deref:false
20736     68/push 0/imm32/next
20737     68/push 0/imm32/next
20738     51/push-ecx/var1
20739     68/push 0x11/imm32/alloc-id:fake
20740     68/push 0x11/imm32/alloc-id:fake:payload
20741     89/<- %edi 4/r32/esp
20742 $test-add-reg-to-reg:initialize-stmt:
20743     # var stmt/esi: (addr statement)
20744     68/push 0/imm32/next
20745     68/push 0/imm32/next
20746     57/push-edi/outputs
20747     68/push 0x11/imm32/alloc-id:fake
20748     56/push-esi/inouts
20749     68/push 0x11/imm32/alloc-id:fake
20750     68/push 0/imm32/operation
20751     68/push 0/imm32/operation
20752     68/push 1/imm32/tag:stmt1
20753     89/<- %esi 4/r32/esp
20754 $test-add-reg-to-reg:initialize-stmt-operation:
20755     # stmt->operation = "add"
20756     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20757     (copy-array Heap "add" %eax)
20758     # convert
20759     c7 0/subop/copy *Curr-block-depth 0/imm32
20760     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
20761     (flush _test-output-buffered-file)
20762 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20768     # check output
20769     (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg")
20770     # . epilogue
20771     89/<- %esp 5/r32/ebp
20772     5d/pop-to-ebp
20773     c3/return
20774 
20775 test-add-reg-to-mem:
20776     #   add-to var1 var2/reg
20777     # =>
20778     #   01/add-to *(ebp+__) var2
20779     #
20780     # . prologue
20781     55/push-ebp
20782     89/<- %ebp 4/r32/esp
20783     # setup
20784     (clear-stream _test-output-stream)
20785     (clear-stream $_test-output-buffered-file->buffer)
20786 $test-add-reg-to-mem:initialize-type:
20787     # var type/ecx: (payload type-tree) = int
20788     68/push 0/imm32/right:null
20789     68/push 0/imm32/right:null
20790     68/push 0/imm32/left:unused
20791     68/push 1/imm32/value:int
20792     68/push 1/imm32/is-atom?:true
20793     68/push 0x11/imm32/alloc-id:fake:payload
20794     89/<- %ecx 4/r32/esp
20795 $test-add-reg-to-mem:initialize-var1:
20796     # var var1/ecx: (payload var)
20797     68/push 0/imm32/register
20798     68/push 0/imm32/register
20799     68/push 8/imm32/stack-offset
20800     68/push 1/imm32/block-depth
20801     51/push-ecx
20802     68/push 0x11/imm32/alloc-id:fake
20803     68/push 0/imm32/name
20804     68/push 0/imm32/name
20805     68/push 0x11/imm32/alloc-id:fake:payload
20806     89/<- %ecx 4/r32/esp
20807 $test-add-reg-to-mem:initialize-var1-name:
20808     # var1->name = "var1"
20809     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20810     (copy-array Heap "var1" %eax)
20811 $test-add-reg-to-mem:initialize-var2:
20812     # var var2/edx: (payload var)
20813     68/push 0/imm32/register
20814     68/push 0/imm32/register
20815     68/push 0/imm32/no-stack-offset
20816     68/push 1/imm32/block-depth
20817     ff 6/subop/push *(ecx+0x10)
20818     68/push 0x11/imm32/alloc-id:fake
20819     68/push 0/imm32/name
20820     68/push 0/imm32/name
20821     68/push 0x11/imm32/alloc-id:fake:payload
20822     89/<- %edx 4/r32/esp
20823 $test-add-reg-to-mem:initialize-var2-name:
20824     # var2->name = "var2"
20825     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
20826     (copy-array Heap "var2" %eax)
20827 $test-add-reg-to-mem:initialize-var2-register:
20828     # var2->register = "ecx"
20829     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
20830     (copy-array Heap "ecx" %eax)
20831 $test-add-reg-to-mem:initialize-inouts:
20832     # var inouts/esi: (payload stmt-var) = [var2]
20833     68/push 0/imm32/is-deref:false
20834     68/push 0/imm32/next
20835     68/push 0/imm32/next
20836     52/push-edx/var2
20837     68/push 0x11/imm32/alloc-id:fake
20838     68/push 0x11/imm32/alloc-id:fake:payload
20839     89/<- %esi 4/r32/esp
20840     # inouts = [var1, var2]
20841     68/push 0/imm32/is-deref:false
20842     56/push-esi/next
20843     68/push 0x11/imm32/alloc-id:fake
20844     51/push-ecx/var1
20845     68/push 0x11/imm32/alloc-id:fake
20846     68/push 0x11/imm32/alloc-id:fake:payload
20847     89/<- %esi 4/r32/esp
20848 $test-add-reg-to-mem:initialize-stmt:
20849     # var stmt/esi: (addr statement)
20850     68/push 0/imm32/next
20851     68/push 0/imm32/next
20852     68/push 0/imm32/outputs
20853     68/push 0/imm32/outputs
20854     56/push-esi/inouts
20855     68/push 0x11/imm32/alloc-id:fake
20856     68/push 0/imm32/operation
20857     68/push 0/imm32/operation
20858     68/push 1/imm32/tag:stmt1
20859     89/<- %esi 4/r32/esp
20860 $test-add-reg-to-mem:initialize-stmt-operation:
20861     # stmt->operation = "add-to"
20862     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20863     (copy-array Heap "add-to" %eax)
20864     # convert
20865     c7 0/subop/copy *Curr-block-depth 0/imm32
20866     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
20867     (flush _test-output-buffered-file)
20868 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20874     # check output
20875     (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem")
20876     # . epilogue
20877     89/<- %esp 5/r32/ebp
20878     5d/pop-to-ebp
20879     c3/return
20880 
20881 test-add-mem-to-reg:
20882     #   var1/reg <- add var2
20883     # =>
20884     #   03/add *(ebp+__) var1
20885     #
20886     # . prologue
20887     55/push-ebp
20888     89/<- %ebp 4/r32/esp
20889     # setup
20890     (clear-stream _test-output-stream)
20891     (clear-stream $_test-output-buffered-file->buffer)
20892 $test-add-mem-to-reg:initialize-type:
20893     # var type/ecx: (payload type-tree) = int
20894     68/push 0/imm32/right:null
20895     68/push 0/imm32/right:null
20896     68/push 0/imm32/left:unused
20897     68/push 1/imm32/value:int
20898     68/push 1/imm32/is-atom?:true
20899     68/push 0x11/imm32/alloc-id:fake:payload
20900     89/<- %ecx 4/r32/esp
20901 $test-add-mem-to-reg:initialize-var:
20902     # var var1/ecx: (payload var)
20903     68/push 0/imm32/register
20904     68/push 0/imm32/register
20905     68/push 0/imm32/no-stack-offset
20906     68/push 1/imm32/block-depth
20907     51/push-ecx
20908     68/push 0x11/imm32/alloc-id:fake
20909     68/push 0/imm32/name
20910     68/push 0/imm32/name
20911     68/push 0x11/imm32/alloc-id:fake:payload
20912     89/<- %ecx 4/r32/esp
20913 $test-add-mem-to-reg:initialize-var-name:
20914     # var1->name = "foo"
20915     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20916     (copy-array Heap "var1" %eax)
20917 $test-add-mem-to-reg:initialize-var-register:
20918     # var1->register = "eax"
20919     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
20920     (copy-array Heap "eax" %eax)
20921 $test-add-mem-to-reg:initialize-var2:
20922     # var var2/edx: (payload var)
20923     68/push 0/imm32/register
20924     68/push 0/imm32/register
20925     68/push 8/imm32/stack-offset
20926     68/push 1/imm32/block-depth
20927     ff 6/subop/push *(ecx+0x10)
20928     68/push 0x11/imm32/alloc-id:fake
20929     68/push 0/imm32/name
20930     68/push 0/imm32/name
20931     68/push 0x11/imm32/alloc-id:fake:payload
20932     89/<- %edx 4/r32/esp
20933 $test-add-mem-to-reg:initialize-var2-name:
20934     # var2->name = "var2"
20935     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
20936     (copy-array Heap "var2" %eax)
20937 $test-add-mem-to-reg:initialize-inouts:
20938     # var inouts/esi: (payload stmt-var) = [var2]
20939     68/push 0/imm32/is-deref:false
20940     68/push 0/imm32/next
20941     68/push 0/imm32/next
20942     52/push-edx/var2
20943     68/push 0x11/imm32/alloc-id:fake
20944     68/push 0x11/imm32/alloc-id:fake:payload
20945     89/<- %esi 4/r32/esp
20946 $test-add-mem-to-reg:initialize-outputs:
20947     # var outputs/edi: (payload stmt-var) = [var1]
20948     68/push 0/imm32/is-deref:false
20949     68/push 0/imm32/next
20950     68/push 0/imm32/next
20951     51/push-ecx/var1
20952     68/push 0x11/imm32/alloc-id:fake
20953     68/push 0x11/imm32/alloc-id:fake:payload
20954     89/<- %edi 4/r32/esp
20955 $test-add-mem-to-reg:initialize-stmt:
20956     # var stmt/esi: (addr statement)
20957     68/push 0/imm32/next
20958     68/push 0/imm32/next
20959     57/push-edi/outputs
20960     68/push 0x11/imm32/alloc-id:fake
20961     56/push-esi/inouts
20962     68/push 0x11/imm32/alloc-id:fake
20963     68/push 0/imm32/operation
20964     68/push 0/imm32/operation
20965     68/push 1/imm32/tag:stmt1
20966     89/<- %esi 4/r32/esp
20967 $test-add-mem-to-reg:initialize-stmt-operation:
20968     # stmt->operation = "add"
20969     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20970     (copy-array Heap "add" %eax)
20971     # convert
20972     c7 0/subop/copy *Curr-block-depth 0/imm32
20973     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
20974     (flush _test-output-buffered-file)
20975 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20981     # check output
20982     (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg")
20983     # . epilogue
20984     89/<- %esp 5/r32/ebp
20985     5d/pop-to-ebp
20986     c3/return
20987 
20988 test-add-literal-to-eax:
20989     #   var1/eax <- add 0x34
20990     # =>
20991     #   05/add-to-eax 0x34/imm32
20992     #
20993     # . prologue
20994     55/push-ebp
20995     89/<- %ebp 4/r32/esp
20996     # setup
20997     (clear-stream _test-output-stream)
20998     (clear-stream $_test-output-buffered-file->buffer)
20999 $test-add-literal-to-eax:initialize-var-type:
21000     # var type/ecx: (payload type-tree) = int
21001     68/push 0/imm32/right:null
21002     68/push 0/imm32/right:null
21003     68/push 0/imm32/left:unused
21004     68/push 1/imm32/value:int
21005     68/push 1/imm32/is-atom?:true
21006     68/push 0x11/imm32/alloc-id:fake:payload
21007     89/<- %ecx 4/r32/esp
21008 $test-add-literal-to-eax:initialize-var:
21009     # var v/ecx: (payload var)
21010     68/push 0/imm32/register
21011     68/push 0/imm32/register
21012     68/push 0/imm32/no-stack-offset
21013     68/push 1/imm32/block-depth
21014     51/push-ecx
21015     68/push 0x11/imm32/alloc-id:fake
21016     68/push 0/imm32/name
21017     68/push 0/imm32/name
21018     68/push 0x11/imm32/alloc-id:fake:payload
21019     89/<- %ecx 4/r32/esp
21020 $test-add-literal-to-eax:initialize-var-name:
21021     # v->name = "v"
21022     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21023     (copy-array Heap "v" %eax)
21024 $test-add-literal-to-eax:initialize-var-register:
21025     # v->register = "eax"
21026     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
21027     (copy-array Heap "eax" %eax)
21028 $test-add-literal-to-eax:initialize-literal-type:
21029     # var type/edx: (payload type-tree) = literal
21030     68/push 0/imm32/right:null
21031     68/push 0/imm32/right:null
21032     68/push 0/imm32/left:unused
21033     68/push 0/imm32/value:literal
21034     68/push 1/imm32/is-atom?:true
21035     68/push 0x11/imm32/alloc-id:fake:payload
21036     89/<- %edx 4/r32/esp
21037 $test-add-literal-to-eax:initialize-literal:
21038     # var l/edx: (payload var)
21039     68/push 0/imm32/register
21040     68/push 0/imm32/register
21041     68/push 0/imm32/no-stack-offset
21042     68/push 1/imm32/block-depth
21043     52/push-edx
21044     68/push 0x11/imm32/alloc-id:fake
21045     68/push 0/imm32/name
21046     68/push 0/imm32/name
21047     68/push 0x11/imm32/alloc-id:fake:payload
21048     89/<- %edx 4/r32/esp
21049 $test-add-literal-to-eax:initialize-literal-value:
21050     # l->name = "0x34"
21051     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21052     (copy-array Heap "0x34" %eax)
21053 $test-add-literal-to-eax:initialize-inouts:
21054     # var inouts/esi: (payload stmt-var) = [l]
21055     68/push 0/imm32/is-deref:false
21056     68/push 0/imm32/next
21057     68/push 0/imm32/next
21058     52/push-edx/l
21059     68/push 0x11/imm32/alloc-id:fake
21060     68/push 0x11/imm32/alloc-id:fake:payload
21061     89/<- %esi 4/r32/esp
21062 $test-add-literal-to-eax:initialize-outputs:
21063     # var outputs/edi: (payload stmt-var) = [v]
21064     68/push 0/imm32/is-deref:false
21065     68/push 0/imm32/next
21066     68/push 0/imm32/next
21067     51/push-ecx/v
21068     68/push 0x11/imm32/alloc-id:fake
21069     68/push 0x11/imm32/alloc-id:fake:payload
21070     89/<- %edi 4/r32/esp
21071 $test-add-literal-to-eax:initialize-stmt:
21072     # var stmt/esi: (addr statement)
21073     68/push 0/imm32/next
21074     68/push 0/imm32/next
21075     57/push-edi/outputs
21076     68/push 0x11/imm32/alloc-id:fake
21077     56/push-esi/inouts
21078     68/push 0x11/imm32/alloc-id:fake
21079     68/push 0/imm32/operation
21080     68/push 0/imm32/operation
21081     68/push 1/imm32/tag:stmt1
21082     89/<- %esi 4/r32/esp
21083 $test-add-literal-to-eax:initialize-stmt-operation:
21084     # stmt->operation = "add"
21085     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21086     (copy-array Heap "add" %eax)
21087     # convert
21088     c7 0/subop/copy *Curr-block-depth 0/imm32
21089     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21090     (flush _test-output-buffered-file)
21091 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21097     # check output
21098     (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax")
21099     # . epilogue
21100     89/<- %esp 5/r32/ebp
21101     5d/pop-to-ebp
21102     c3/return
21103 
21104 test-add-literal-to-reg:
21105     #   var1/ecx <- add 0x34
21106     # =>
21107     #   81 0/subop/add %ecx 0x34/imm32
21108     #
21109     # . prologue
21110     55/push-ebp
21111     89/<- %ebp 4/r32/esp
21112     # setup
21113     (clear-stream _test-output-stream)
21114     (clear-stream $_test-output-buffered-file->buffer)
21115 $test-add-literal-to-reg:initialize-var-type:
21116     # var type/ecx: (payload type-tree) = int
21117     68/push 0/imm32/right:null
21118     68/push 0/imm32/right:null
21119     68/push 0/imm32/left:unused
21120     68/push 1/imm32/value:int
21121     68/push 1/imm32/is-atom?:true
21122     68/push 0x11/imm32/alloc-id:fake:payload
21123     89/<- %ecx 4/r32/esp
21124 $test-add-literal-to-reg:initialize-var:
21125     # var v/ecx: (payload var)
21126     68/push 0/imm32/register
21127     68/push 0/imm32/register
21128     68/push 0/imm32/no-stack-offset
21129     68/push 1/imm32/block-depth
21130     51/push-ecx
21131     68/push 0x11/imm32/alloc-id:fake
21132     68/push 0/imm32/name
21133     68/push 0/imm32/name
21134     68/push 0x11/imm32/alloc-id:fake:payload
21135     89/<- %ecx 4/r32/esp
21136 $test-add-literal-to-reg:initialize-var-name:
21137     # v->name = "v"
21138     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21139     (copy-array Heap "v" %eax)
21140 $test-add-literal-to-reg:initialize-var-register:
21141     # v->register = "ecx"
21142     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
21143     (copy-array Heap "ecx" %eax)
21144 $test-add-literal-to-reg:initialize-literal-type:
21145     # var type/edx: (payload type-tree) = literal
21146     68/push 0/imm32/right:null
21147     68/push 0/imm32/right:null
21148     68/push 0/imm32/left:unused
21149     68/push 0/imm32/value:literal
21150     68/push 1/imm32/is-atom?:true
21151     68/push 0x11/imm32/alloc-id:fake:payload
21152     89/<- %edx 4/r32/esp
21153 $test-add-literal-to-reg:initialize-literal:
21154     # var l/edx: (payload var)
21155     68/push 0/imm32/register
21156     68/push 0/imm32/register
21157     68/push 0/imm32/no-stack-offset
21158     68/push 1/imm32/block-depth
21159     52/push-edx
21160     68/push 0x11/imm32/alloc-id:fake
21161     68/push 0/imm32/name
21162     68/push 0/imm32/name
21163     68/push 0x11/imm32/alloc-id:fake:payload
21164     89/<- %edx 4/r32/esp
21165 $test-add-literal-to-reg:initialize-literal-value:
21166     # l->name = "0x34"
21167     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21168     (copy-array Heap "0x34" %eax)
21169 $test-add-literal-to-reg:initialize-inouts:
21170     # var inouts/esi: (payload stmt-var) = [l]
21171     68/push 0/imm32/is-deref:false
21172     68/push 0/imm32/next
21173     68/push 0/imm32/next
21174     52/push-edx/l
21175     68/push 0x11/imm32/alloc-id:fake
21176     68/push 0x11/imm32/alloc-id:fake:payload
21177     89/<- %esi 4/r32/esp
21178 $test-add-literal-to-reg:initialize-outputs:
21179     # var outputs/edi: (payload stmt-var) = [v]
21180     68/push 0/imm32/is-deref:false
21181     68/push 0/imm32/next
21182     68/push 0/imm32/next
21183     51/push-ecx/v
21184     68/push 0x11/imm32/alloc-id:fake
21185     68/push 0x11/imm32/alloc-id:fake:payload
21186     89/<- %edi 4/r32/esp
21187 $test-add-literal-to-reg:initialize-stmt:
21188     # var stmt/esi: (addr statement)
21189     68/push 0/imm32/next
21190     68/push 0/imm32/next
21191     57/push-edi/outputs
21192     68/push 0x11/imm32/alloc-id:fake
21193     56/push-esi/inouts
21194     68/push 0x11/imm32/alloc-id:fake
21195     68/push 0/imm32/operation
21196     68/push 0/imm32/operation
21197     68/push 1/imm32/tag:stmt1
21198     89/<- %esi 4/r32/esp
21199 $test-add-literal-to-reg:initialize-stmt-operation:
21200     # stmt->operation = "add"
21201     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21202     (copy-array Heap "add" %eax)
21203     # convert
21204     c7 0/subop/copy *Curr-block-depth 0/imm32
21205     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21206     (flush _test-output-buffered-file)
21207 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21213     # check output
21214     (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg")
21215     # . epilogue
21216     89/<- %esp 5/r32/ebp
21217     5d/pop-to-ebp
21218     c3/return
21219 
21220 test-add-literal-to-mem:
21221     #   add-to var1, 0x34
21222     # =>
21223     #   81 0/subop/add %eax 0x34/imm32
21224     #
21225     # . prologue
21226     55/push-ebp
21227     89/<- %ebp 4/r32/esp
21228     # setup
21229     (clear-stream _test-output-stream)
21230     (clear-stream $_test-output-buffered-file->buffer)
21231 $test-add-literal-to-mem:initialize-type:
21232     # var type/ecx: (payload type-tree) = int
21233     68/push 0/imm32/right:null
21234     68/push 0/imm32/right:null
21235     68/push 0/imm32/left:unused
21236     68/push 1/imm32/value:int
21237     68/push 1/imm32/is-atom?:true
21238     68/push 0x11/imm32/alloc-id:fake:payload
21239     89/<- %ecx 4/r32/esp
21240 $test-add-literal-to-mem:initialize-var1:
21241     # var var1/ecx: (payload var)
21242     68/push 0/imm32/register
21243     68/push 0/imm32/register
21244     68/push 8/imm32/stack-offset
21245     68/push 1/imm32/block-depth
21246     51/push-ecx
21247     68/push 0x11/imm32/alloc-id:fake
21248     68/push 0/imm32/name
21249     68/push 0/imm32/name
21250     68/push 0x11/imm32/alloc-id:fake:payload
21251     89/<- %ecx 4/r32/esp
21252 $test-add-literal-to-mem:initialize-var1-name:
21253     # var1->name = "var1"
21254     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21255     (copy-array Heap "var1" %eax)
21256 $test-add-literal-to-mem:initialize-literal-type:
21257     # var type/edx: (payload type-tree) = literal
21258     68/push 0/imm32/right:null
21259     68/push 0/imm32/right:null
21260     68/push 0/imm32/left:unused
21261     68/push 0/imm32/value:literal
21262     68/push 1/imm32/is-atom?:true
21263     68/push 0x11/imm32/alloc-id:fake:payload
21264     89/<- %edx 4/r32/esp
21265 $test-add-literal-to-mem:initialize-literal:
21266     # var l/edx: (payload var)
21267     68/push 0/imm32/register
21268     68/push 0/imm32/register
21269     68/push 0/imm32/no-stack-offset
21270     68/push 1/imm32/block-depth
21271     52/push-edx
21272     68/push 0x11/imm32/alloc-id:fake
21273     68/push 0/imm32/name
21274     68/push 0/imm32/name
21275     68/push 0x11/imm32/alloc-id:fake:payload
21276     89/<- %edx 4/r32/esp
21277 $test-add-literal-to-mem:initialize-literal-value:
21278     # l->name = "0x34"
21279     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21280     (copy-array Heap "0x34" %eax)
21281 $test-add-literal-to-mem:initialize-inouts:
21282     # var inouts/esi: (payload stmt-var) = [l]
21283     68/push 0/imm32/is-deref:false
21284     68/push 0/imm32/next
21285     68/push 0/imm32/next
21286     52/push-edx/l
21287     68/push 0x11/imm32/alloc-id:fake
21288     68/push 0x11/imm32/alloc-id:fake:payload
21289     89/<- %esi 4/r32/esp
21290     # var inouts = (handle stmt-var) = [var1, var2]
21291     68/push 0/imm32/is-deref:false
21292     56/push-esi/next
21293     68/push 0x11/imm32/alloc-id:fake
21294     51/push-ecx/var1
21295     68/push 0x11/imm32/alloc-id:fake
21296     68/push 0x11/imm32/alloc-id:fake:payload
21297     89/<- %esi 4/r32/esp
21298 $test-add-literal-to-mem:initialize-stmt:
21299     # var stmt/esi: (addr statement)
21300     68/push 0/imm32/next
21301     68/push 0/imm32/next
21302     68/push 0/imm32/outputs
21303     68/push 0/imm32/outputs
21304     56/push-esi/inouts
21305     68/push 0x11/imm32/alloc-id:fake
21306     68/push 0/imm32/operation
21307     68/push 0/imm32/operation
21308     68/push 1/imm32/tag:stmt1
21309     89/<- %esi 4/r32/esp
21310 $test-add-literal-to-mem:initialize-stmt-operation:
21311     # stmt->operation = "add-to"
21312     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21313     (copy-array Heap "add-to" %eax)
21314     # convert
21315     c7 0/subop/copy *Curr-block-depth 0/imm32
21316     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21317     (flush _test-output-buffered-file)
21318 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21324     # check output
21325     (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem")
21326     # . epilogue
21327     89/<- %esp 5/r32/ebp
21328     5d/pop-to-ebp
21329     c3/return
21330 
21331 test-shift-reg-by-literal:
21332     #   var1/ecx <- shift-left 2
21333     # =>
21334     #   c1/shift 4/subop/left %ecx 2/imm8
21335     #
21336     # . prologue
21337     55/push-ebp
21338     89/<- %ebp 4/r32/esp
21339     # setup
21340     (clear-stream _test-output-stream)
21341     (clear-stream $_test-output-buffered-file->buffer)
21342 $test-shift-reg-by-literal:initialize-var-type:
21343     # var type/ecx: (payload type-tree) = int
21344     68/push 0/imm32/right:null
21345     68/push 0/imm32/right:null
21346     68/push 0/imm32/left:unused
21347     68/push 1/imm32/value:int
21348     68/push 1/imm32/is-atom?:true
21349     68/push 0x11/imm32/alloc-id:fake:payload
21350     89/<- %ecx 4/r32/esp
21351 $test-shift-reg-by-literal:initialize-var:
21352     # var v/ecx: (payload var)
21353     68/push 0/imm32/register
21354     68/push 0/imm32/register
21355     68/push 0/imm32/no-stack-offset
21356     68/push 1/imm32/block-depth
21357     51/push-ecx
21358     68/push 0x11/imm32/alloc-id:fake
21359     68/push 0/imm32/name
21360     68/push 0/imm32/name
21361     68/push 0x11/imm32/alloc-id:fake:payload
21362     89/<- %ecx 4/r32/esp
21363 $test-shift-reg-by-literal:initialize-var-name:
21364     # v->name = "v"
21365     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21366     (copy-array Heap "v" %eax)
21367 $test-shift-reg-by-literal:initialize-var-register:
21368     # v->register = "ecx"
21369     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
21370     (copy-array Heap "ecx" %eax)
21371 $test-shift-reg-by-literal:initialize-literal-type:
21372     # var type/edx: (payload type-tree) = literal
21373     68/push 0/imm32/right:null
21374     68/push 0/imm32/right:null
21375     68/push 0/imm32/left:unused
21376     68/push 0/imm32/value:literal
21377     68/push 1/imm32/is-atom?:true
21378     68/push 0x11/imm32/alloc-id:fake:payload
21379     89/<- %edx 4/r32/esp
21380 $test-shift-reg-by-literal:initialize-literal:
21381     # var l/edx: (payload var)
21382     68/push 0/imm32/register
21383     68/push 0/imm32/register
21384     68/push 0/imm32/no-stack-offset
21385     68/push 1/imm32/block-depth
21386     52/push-edx
21387     68/push 0x11/imm32/alloc-id:fake
21388     68/push 0/imm32/name
21389     68/push 0/imm32/name
21390     68/push 0x11/imm32/alloc-id:fake:payload
21391     89/<- %edx 4/r32/esp
21392 $test-shift-reg-by-literal:initialize-literal-value:
21393     # l->name = "2"
21394     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21395     (copy-array Heap "2" %eax)
21396 $test-shift-reg-by-literal:initialize-inouts:
21397     # var inouts/esi: (payload stmt-var) = [l]
21398     68/push 0/imm32/is-deref:false
21399     68/push 0/imm32/next
21400     68/push 0/imm32/next
21401     52/push-edx/l
21402     68/push 0x11/imm32/alloc-id:fake
21403     68/push 0x11/imm32/alloc-id:fake:payload
21404     89/<- %esi 4/r32/esp
21405 $test-shift-reg-by-literal:initialize-outputs:
21406     # var outputs/edi: (payload stmt-var) = [v]
21407     68/push 0/imm32/is-deref:false
21408     68/push 0/imm32/next
21409     68/push 0/imm32/next
21410     51/push-ecx/v
21411     68/push 0x11/imm32/alloc-id:fake
21412     68/push 0x11/imm32/alloc-id:fake:payload
21413     89/<- %edi 4/r32/esp
21414 $test-shift-reg-by-literal:initialize-stmt:
21415     # var stmt/esi: (addr statement)
21416     68/push 0/imm32/next
21417     68/push 0/imm32/next
21418     57/push-edi/outputs
21419     68/push 0x11/imm32/alloc-id:fake
21420     56/push-esi/inouts
21421     68/push 0x11/imm32/alloc-id:fake
21422     68/push 0/imm32/operation
21423     68/push 0/imm32/operation
21424     68/push 1/imm32/tag:stmt1
21425     89/<- %esi 4/r32/esp
21426 $test-shift-reg-by-literal:initialize-stmt-operation:
21427     # stmt->operation = "shift-left"
21428     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21429     (copy-array Heap "shift-left" %eax)
21430     # convert
21431     c7 0/subop/copy *Curr-block-depth 0/imm32
21432     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21433     (flush _test-output-buffered-file)
21434 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21440     # check output
21441     (check-next-stream-line-equal _test-output-stream "c1/shift 4/subop/left %ecx 2/imm8" "F - test-shift-reg-by-literal")
21442     # . epilogue
21443     89/<- %esp 5/r32/ebp
21444     5d/pop-to-ebp
21445     c3/return
21446 
21447 test-shift-mem-by-literal:
21448     #   shift-left var 3
21449     # =>
21450     #   c1/shift 4/subop/left *(ebp+8) 3/imm8
21451     #
21452     # . prologue
21453     55/push-ebp
21454     89/<- %ebp 4/r32/esp
21455     # setup
21456     (clear-stream _test-output-stream)
21457     (clear-stream $_test-output-buffered-file->buffer)
21458 $test-shift-mem-by-literal:initialize-type:
21459     # var type/ecx: (payload type-tree) = int
21460     68/push 0/imm32/right:null
21461     68/push 0/imm32/right:null
21462     68/push 0/imm32/left:unused
21463     68/push 1/imm32/value:int
21464     68/push 1/imm32/is-atom?:true
21465     68/push 0x11/imm32/alloc-id:fake:payload
21466     89/<- %ecx 4/r32/esp
21467 $test-shift-mem-by-literal:initialize-var1:
21468     # var var1/ecx: (payload var)
21469     68/push 0/imm32/register
21470     68/push 0/imm32/register
21471     68/push 8/imm32/stack-offset
21472     68/push 1/imm32/block-depth
21473     51/push-ecx
21474     68/push 0x11/imm32/alloc-id:fake
21475     68/push 0/imm32/name
21476     68/push 0/imm32/name
21477     68/push 0x11/imm32/alloc-id:fake:payload
21478     89/<- %ecx 4/r32/esp
21479 $test-shift-mem-by-literal:initialize-var1-name:
21480     # var1->name = "var1"
21481     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21482     (copy-array Heap "var1" %eax)
21483 $test-shift-mem-by-literal:initialize-literal-type:
21484     # var type/edx: (payload type-tree) = literal
21485     68/push 0/imm32/right:null
21486     68/push 0/imm32/right:null
21487     68/push 0/imm32/left:unused
21488     68/push 0/imm32/value:literal
21489     68/push 1/imm32/is-atom?:true
21490     68/push 0x11/imm32/alloc-id:fake:payload
21491     89/<- %edx 4/r32/esp
21492 $test-shift-mem-by-literal:initialize-literal:
21493     # var l/edx: (payload var)
21494     68/push 0/imm32/register
21495     68/push 0/imm32/register
21496     68/push 0/imm32/no-stack-offset
21497     68/push 1/imm32/block-depth
21498     52/push-edx
21499     68/push 0x11/imm32/alloc-id:fake
21500     68/push 0/imm32/name
21501     68/push 0/imm32/name
21502     68/push 0x11/imm32/alloc-id:fake:payload
21503     89/<- %edx 4/r32/esp
21504 $test-shift-mem-by-literal:initialize-literal-value:
21505     # l->name = "3"
21506     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21507     (copy-array Heap "3" %eax)
21508 $test-shift-mem-by-literal:initialize-inouts:
21509     # var inouts/esi: (payload stmt-var) = [l]
21510     68/push 0/imm32/is-deref:false
21511     68/push 0/imm32/next
21512     68/push 0/imm32/next
21513     52/push-edx/l
21514     68/push 0x11/imm32/alloc-id:fake
21515     68/push 0x11/imm32/alloc-id:fake:payload
21516     89/<- %esi 4/r32/esp
21517     # var inouts = (handle stmt-var) = [var1, var2]
21518     68/push 0/imm32/is-deref:false
21519     56/push-esi/next
21520     68/push 0x11/imm32/alloc-id:fake
21521     51/push-ecx/var1
21522     68/push 0x11/imm32/alloc-id:fake
21523     68/push 0x11/imm32/alloc-id:fake:payload
21524     89/<- %esi 4/r32/esp
21525 $test-shift-mem-by-literal:initialize-stmt:
21526     # var stmt/esi: (addr statement)
21527     68/push 0/imm32/next
21528     68/push 0/imm32/next
21529     68/push 0/imm32/outputs
21530     68/push 0/imm32/outputs
21531     56/push-esi/inouts
21532     68/push 0x11/imm32/alloc-id:fake
21533     68/push 0/imm32/operation
21534     68/push 0/imm32/operation
21535     68/push 1/imm32/tag:stmt1
21536     89/<- %esi 4/r32/esp
21537 $test-shift-mem-by-literal:initialize-stmt-operation:
21538     # stmt->operation = "shift-left"
21539     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21540     (copy-array Heap "shift-left" %eax)
21541     # convert
21542     c7 0/subop/copy *Curr-block-depth 0/imm32
21543     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21544     (flush _test-output-buffered-file)
21545 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21551     # check output
21552     (check-next-stream-line-equal _test-output-stream "c1/shift 4/subop/left *(ebp+0x00000008) 3/imm8" "F - test-shift-mem-by-literal")
21553     # . epilogue
21554     89/<- %esp 5/r32/ebp
21555     5d/pop-to-ebp
21556     c3/return
21557 
21558 test-compare-reg-with-reg:
21559     #   compare var1/ecx, var2/eax
21560     # =>
21561     #   39/compare %ecx 0/r32/eax
21562     #
21563     # . prologue
21564     55/push-ebp
21565     89/<- %ebp 4/r32/esp
21566     # setup
21567     (clear-stream _test-output-stream)
21568     (clear-stream $_test-output-buffered-file->buffer)
21569 $test-compare-reg-with-reg:initialize-type:
21570     # var type/ecx: (payload type-tree) = int
21571     68/push 0/imm32/right:null
21572     68/push 0/imm32/right:null
21573     68/push 0/imm32/left:unused
21574     68/push 1/imm32/value:int
21575     68/push 1/imm32/is-atom?:true
21576     68/push 0x11/imm32/alloc-id:fake:payload
21577     89/<- %ecx 4/r32/esp
21578 $test-compare-reg-with-reg:initialize-var1:
21579     # var var1/ecx: (payload var)
21580     68/push 0/imm32/register
21581     68/push 0/imm32/register
21582     68/push 0/imm32/no-stack-offset
21583     68/push 1/imm32/block-depth
21584     51/push-ecx
21585     68/push 0x11/imm32/alloc-id:fake
21586     68/push 0/imm32/name
21587     68/push 0/imm32/name
21588     68/push 0x11/imm32/alloc-id:fake:payload
21589     89/<- %ecx 4/r32/esp
21590 $test-compare-reg-with-reg:initialize-var1-name:
21591     # var1->name = "var1"
21592     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21593     (copy-array Heap "var1" %eax)
21594 $test-compare-reg-with-reg:initialize-var1-register:
21595     # var1->register = "ecx"
21596     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
21597     (copy-array Heap "ecx" %eax)
21598 $test-compare-reg-with-reg:initialize-var2:
21599     # var var2/edx: (payload var)
21600     68/push 0/imm32/register
21601     68/push 0/imm32/register
21602     68/push 0/imm32/no-stack-offset
21603     68/push 1/imm32/block-depth
21604     ff 6/subop/push *(ecx+0x10)
21605     68/push 0x11/imm32/alloc-id:fake
21606     68/push 0/imm32/name
21607     68/push 0/imm32/name
21608     68/push 0x11/imm32/alloc-id:fake:payload
21609     89/<- %edx 4/r32/esp
21610 $test-compare-reg-with-reg:initialize-var2-name:
21611     # var2->name = "var2"
21612     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21613     (copy-array Heap "var2" %eax)
21614 $test-compare-reg-with-reg:initialize-var2-register:
21615     # var2->register = "eax"
21616     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
21617     (copy-array Heap "eax" %eax)
21618 $test-compare-reg-with-reg:initialize-inouts:
21619     # var inouts/esi: (payload stmt-var) = [var2]
21620     68/push 0/imm32/is-deref:false
21621     68/push 0/imm32/next
21622     68/push 0/imm32/next
21623     52/push-edx/var2
21624     68/push 0x11/imm32/alloc-id:fake
21625     68/push 0x11/imm32/alloc-id:fake:payload
21626     89/<- %esi 4/r32/esp
21627     # inouts = [var1, var2]
21628     68/push 0/imm32/is-deref:false
21629     56/push-esi/next
21630     68/push 0x11/imm32/alloc-id:fake
21631     51/push-ecx/var1
21632     68/push 0x11/imm32/alloc-id:fake
21633     68/push 0x11/imm32/alloc-id:fake:payload
21634     89/<- %esi 4/r32/esp
21635 $test-compare-reg-with-reg:initialize-stmt:
21636     # var stmt/esi: (addr statement)
21637     68/push 0/imm32/next
21638     68/push 0/imm32/next
21639     68/push 0/imm32/outputs
21640     68/push 0/imm32/outputs
21641     56/push-esi/inouts
21642     68/push 0x11/imm32/alloc-id:fake
21643     68/push 0/imm32/operation
21644     68/push 0/imm32/operation
21645     68/push 1/imm32/tag:stmt1
21646     89/<- %esi 4/r32/esp
21647 $test-compare-reg-with-reg:initialize-stmt-operation:
21648     # stmt->operation = "compare"
21649     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21650     (copy-array Heap "compare" %eax)
21651     # convert
21652     c7 0/subop/copy *Curr-block-depth 0/imm32
21653     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21654     (flush _test-output-buffered-file)
21655 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21661     # check output
21662     (check-next-stream-line-equal _test-output-stream "39/compare-> %ecx 0x00000000/r32" "F - test-compare-reg-with-reg")
21663     # . epilogue
21664     89/<- %esp 5/r32/ebp
21665     5d/pop-to-ebp
21666     c3/return
21667 
21668 test-compare-mem-with-reg:
21669     #   compare var1, var2/eax
21670     # =>
21671     #   39/compare *(ebp+___) 0/r32/eax
21672     #
21673     # . prologue
21674     55/push-ebp
21675     89/<- %ebp 4/r32/esp
21676     # setup
21677     (clear-stream _test-output-stream)
21678     (clear-stream $_test-output-buffered-file->buffer)
21679 $test-compare-mem-with-reg:initialize-type:
21680     # var type/ecx: (payload type-tree) = int
21681     68/push 0/imm32/right:null
21682     68/push 0/imm32/right:null
21683     68/push 0/imm32/left:unused
21684     68/push 1/imm32/value:int
21685     68/push 1/imm32/is-atom?:true
21686     68/push 0x11/imm32/alloc-id:fake:payload
21687     89/<- %ecx 4/r32/esp
21688 $test-compare-mem-with-reg:initialize-var1:
21689     # var var1/ecx: (payload var)
21690     68/push 0/imm32/register
21691     68/push 0/imm32/register
21692     68/push 8/imm32/stack-offset
21693     68/push 1/imm32/block-depth
21694     51/push-ecx
21695     68/push 0x11/imm32/alloc-id:fake
21696     68/push 0/imm32/name
21697     68/push 0/imm32/name
21698     68/push 0x11/imm32/alloc-id:fake:payload
21699     89/<- %ecx 4/r32/esp
21700 $test-compare-mem-with-reg:initialize-var1-name:
21701     # var1->name = "var1"
21702     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21703     (copy-array Heap "var1" %eax)
21704 $test-compare-mem-with-reg:initialize-var2:
21705     # var var2/edx: (payload var)
21706     68/push 0/imm32/register
21707     68/push 0/imm32/register
21708     68/push 0/imm32/no-stack-offset
21709     68/push 1/imm32/block-depth
21710     ff 6/subop/push *(ecx+0x10)
21711     68/push 0x11/imm32/alloc-id:fake
21712     68/push 0/imm32/name
21713     68/push 0/imm32/name
21714     68/push 0x11/imm32/alloc-id:fake:payload
21715     89/<- %edx 4/r32/esp
21716 $test-compare-mem-with-reg:initialize-var2-name:
21717     # var2->name = "var2"
21718     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21719     (copy-array Heap "var2" %eax)
21720 $test-compare-mem-with-reg:initialize-var2-register:
21721     # var2->register = "eax"
21722     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
21723     (copy-array Heap "eax" %eax)
21724 $test-compare-mem-with-reg:initialize-inouts:
21725     # var inouts/esi: (payload stmt-var) = [var2]
21726     68/push 0/imm32/is-deref:false
21727     68/push 0/imm32/next
21728     68/push 0/imm32/next
21729     52/push-edx/var2
21730     68/push 0x11/imm32/alloc-id:fake
21731     68/push 0x11/imm32/alloc-id:fake:payload
21732     89/<- %esi 4/r32/esp
21733     # inouts = [var1, var2]
21734     68/push 0/imm32/is-deref:false
21735     56/push-esi/next
21736     68/push 0x11/imm32/alloc-id:fake
21737     51/push-ecx/var1
21738     68/push 0x11/imm32/alloc-id:fake
21739     68/push 0x11/imm32/alloc-id:fake:payload
21740     89/<- %esi 4/r32/esp
21741 $test-compare-mem-with-reg:initialize-stmt:
21742     # var stmt/esi: (addr statement)
21743     68/push 0/imm32/next
21744     68/push 0/imm32/next
21745     68/push 0/imm32/outputs
21746     68/push 0/imm32/outputs
21747     56/push-esi/inouts
21748     68/push 0x11/imm32/alloc-id:fake
21749     68/push 0/imm32/operation
21750     68/push 0/imm32/operation
21751     68/push 1/imm32/tag:stmt1
21752     89/<- %esi 4/r32/esp
21753 $test-compare-mem-with-reg:initialize-stmt-operation:
21754     # stmt->operation = "compare"
21755     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21756     (copy-array Heap "compare" %eax)
21757     # convert
21758     c7 0/subop/copy *Curr-block-depth 0/imm32
21759     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21760     (flush _test-output-buffered-file)
21761 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21767     # check output
21768     (check-next-stream-line-equal _test-output-stream "39/compare-> *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-mem-with-reg")
21769     # . epilogue
21770     89/<- %esp 5/r32/ebp
21771     5d/pop-to-ebp
21772     c3/return
21773 
21774 test-compare-reg-with-mem:
21775     #   compare var1/eax, var2
21776     # =>
21777     #   3b/compare<- *(ebp+___) 0/r32/eax
21778     #
21779     # . prologue
21780     55/push-ebp
21781     89/<- %ebp 4/r32/esp
21782     # setup
21783     (clear-stream _test-output-stream)
21784     (clear-stream $_test-output-buffered-file->buffer)
21785 $test-compare-reg-with-mem:initialize-type:
21786     # var type/ecx: (payload type-tree) = int
21787     68/push 0/imm32/right:null
21788     68/push 0/imm32/right:null
21789     68/push 0/imm32/left:unused
21790     68/push 1/imm32/value:int
21791     68/push 1/imm32/is-atom?:true
21792     68/push 0x11/imm32/alloc-id:fake:payload
21793     89/<- %ecx 4/r32/esp
21794 $test-compare-reg-with-mem:initialize-var1:
21795     # var var1/ecx: (payload var)
21796     68/push 0/imm32/register
21797     68/push 0/imm32/register
21798     68/push 0/imm32/no-stack-offset
21799     68/push 1/imm32/block-depth
21800     51/push-ecx
21801     68/push 0x11/imm32/alloc-id:fake
21802     68/push 0/imm32/name
21803     68/push 0/imm32/name
21804     68/push 0x11/imm32/alloc-id:fake:payload
21805     89/<- %ecx 4/r32/esp
21806 $test-compare-reg-with-mem:initialize-var1-name:
21807     # var1->name = "var1"
21808     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21809     (copy-array Heap "var1" %eax)
21810 $test-compare-reg-with-mem:initialize-var1-register:
21811     # var1->register = "eax"
21812     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
21813     (copy-array Heap "eax" %eax)
21814 $test-compare-reg-with-mem:initialize-var2:
21815     # var var2/edx: (payload var)
21816     68/push 0/imm32/register
21817     68/push 0/imm32/register
21818     68/push 8/imm32/stack-offset
21819     68/push 1/imm32/block-depth
21820     ff 6/subop/push *(ecx+0x10)
21821     68/push 0x11/imm32/alloc-id:fake
21822     68/push 0/imm32/name
21823     68/push 0/imm32/name
21824     68/push 0x11/imm32/alloc-id:fake:payload
21825     89/<- %edx 4/r32/esp
21826 $test-compare-reg-with-mem:initialize-var2-name:
21827     # var2->name = "var2"
21828     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21829     (copy-array Heap "var2" %eax)
21830 $test-compare-reg-with-mem:initialize-inouts:
21831     # var inouts/esi: (payload stmt-var) = [var2]
21832     68/push 0/imm32/is-deref:false
21833     68/push 0/imm32/next
21834     68/push 0/imm32/next
21835     52/push-edx/var2
21836     68/push 0x11/imm32/alloc-id:fake
21837     68/push 0x11/imm32/alloc-id:fake:payload
21838     89/<- %esi 4/r32/esp
21839     # inouts = [var1, var2]
21840     68/push 0/imm32/is-deref:false
21841     56/push-esi/next
21842     68/push 0x11/imm32/alloc-id:fake
21843     51/push-ecx/var1
21844     68/push 0x11/imm32/alloc-id:fake
21845     68/push 0x11/imm32/alloc-id:fake:payload
21846     89/<- %esi 4/r32/esp
21847 $test-compare-reg-with-mem:initialize-stmt:
21848     # var stmt/esi: (addr statement)
21849     68/push 0/imm32/next
21850     68/push 0/imm32/next
21851     68/push 0/imm32/outputs
21852     68/push 0/imm32/outputs
21853     56/push-esi/inouts
21854     68/push 0x11/imm32/alloc-id:fake
21855     68/push 0/imm32/operation
21856     68/push 0/imm32/operation
21857     68/push 1/imm32/tag:stmt1
21858     89/<- %esi 4/r32/esp
21859 $test-compare-reg-with-mem:initialize-stmt-operation:
21860     # stmt->operation = "compare"
21861     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21862     (copy-array Heap "compare" %eax)
21863     # convert
21864     c7 0/subop/copy *Curr-block-depth 0/imm32
21865     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21866     (flush _test-output-buffered-file)
21867 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21873     # check output
21874     (check-next-stream-line-equal _test-output-stream "3b/compare<- *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-reg-with-mem")
21875     # . epilogue
21876     89/<- %esp 5/r32/ebp
21877     5d/pop-to-ebp
21878     c3/return
21879 
21880 test-compare-mem-with-literal:
21881     #   compare var1, 0x34
21882     # =>
21883     #   81 7/subop/compare *(ebp+___) 0x34/imm32
21884     #
21885     # . prologue
21886     55/push-ebp
21887     89/<- %ebp 4/r32/esp
21888     # setup
21889     (clear-stream _test-output-stream)
21890     (clear-stream $_test-output-buffered-file->buffer)
21891 $test-compare-mem-with-literal:initialize-type:
21892     # var type/ecx: (payload type-tree) = int
21893     68/push 0/imm32/right:null
21894     68/push 0/imm32/right:null
21895     68/push 0/imm32/left:unused
21896     68/push 1/imm32/value:int
21897     68/push 1/imm32/is-atom?:true
21898     68/push 0x11/imm32/alloc-id:fake:payload
21899     89/<- %ecx 4/r32/esp
21900 $test-compare-mem-with-literal:initialize-var1:
21901     # var var1/ecx: (payload var)
21902     68/push 0/imm32/register
21903     68/push 0/imm32/register
21904     68/push 8/imm32/stack-offset
21905     68/push 1/imm32/block-depth
21906     51/push-ecx
21907     68/push 0x11/imm32/alloc-id:fake
21908     68/push 0/imm32/name
21909     68/push 0/imm32/name
21910     68/push 0x11/imm32/alloc-id:fake:payload
21911     89/<- %ecx 4/r32/esp
21912 $test-compare-mem-with-literal:initialize-var1-name:
21913     # var1->name = "var1"
21914     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21915     (copy-array Heap "var1" %eax)
21916 $test-compare-mem-with-literal:initialize-literal-type:
21917     # var type/edx: (payload type-tree) = literal
21918     68/push 0/imm32/right:null
21919     68/push 0/imm32/right:null
21920     68/push 0/imm32/left:unused
21921     68/push 0/imm32/value:literal
21922     68/push 1/imm32/is-atom?:true
21923     68/push 0x11/imm32/alloc-id:fake:payload
21924     89/<- %edx 4/r32/esp
21925 $test-compare-mem-with-literal:initialize-literal:
21926     # var l/edx: (payload var)
21927     68/push 0/imm32/register
21928     68/push 0/imm32/register
21929     68/push 0/imm32/no-stack-offset
21930     68/push 1/imm32/block-depth
21931     52/push-edx
21932     68/push 0x11/imm32/alloc-id:fake
21933     68/push 0/imm32/name
21934     68/push 0/imm32/name
21935     68/push 0x11/imm32/alloc-id:fake:payload
21936     89/<- %edx 4/r32/esp
21937 $test-compare-mem-with-literal:initialize-literal-value:
21938     # l->name = "0x34"
21939     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21940     (copy-array Heap "0x34" %eax)
21941 $test-compare-mem-with-literal:initialize-inouts:
21942     # var inouts/esi: (payload stmt-var) = [l]
21943     68/push 0/imm32/is-deref:false
21944     68/push 0/imm32/next
21945     68/push 0/imm32/next
21946     52/push-edx/l
21947     68/push 0x11/imm32/alloc-id:fake
21948     68/push 0x11/imm32/alloc-id:fake:payload
21949     89/<- %esi 4/r32/esp
21950     # var inouts = (handle stmt-var) = [var1, var2]
21951     68/push 0/imm32/is-deref:false
21952     56/push-esi/next
21953     68/push 0x11/imm32/alloc-id:fake
21954     51/push-ecx/var1
21955     68/push 0x11/imm32/alloc-id:fake
21956     68/push 0x11/imm32/alloc-id:fake:payload
21957     89/<- %esi 4/r32/esp
21958 $test-compare-mem-with-literal:initialize-stmt:
21959     # var stmt/esi: (addr statement)
21960     68/push 0/imm32/next
21961     68/push 0/imm32/next
21962     68/push 0/imm32/outputs
21963     68/push 0/imm32/outputs
21964     56/push-esi/inouts
21965     68/push 0x11/imm32/alloc-id:fake
21966     68/push 0/imm32/operation
21967     68/push 0/imm32/operation
21968     68/push 1/imm32/tag:stmt1
21969     89/<- %esi 4/r32/esp
21970 $test-compare-mem-with-literal:initialize-stmt-operation:
21971     # stmt->operation = "compare"
21972     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21973     (copy-array Heap "compare" %eax)
21974     # convert
21975     c7 0/subop/copy *Curr-block-depth 0/imm32
21976     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21977     (flush _test-output-buffered-file)
21978 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21984     # check output
21985     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare *(ebp+0x00000008) 0x34/imm32" "F - test-compare-mem-with-literal")
21986     # . epilogue
21987     89/<- %esp 5/r32/ebp
21988     5d/pop-to-ebp
21989     c3/return
21990 
21991 test-compare-eax-with-literal:
21992     #   compare var1/eax 0x34
21993     # =>
21994     #   3d/compare-eax-with 0x34/imm32
21995     #
21996     # . prologue
21997     55/push-ebp
21998     89/<- %ebp 4/r32/esp
21999     # setup
22000     (clear-stream _test-output-stream)
22001     (clear-stream $_test-output-buffered-file->buffer)
22002 $test-compare-eax-with-literal:initialize-type:
22003     # var type/ecx: (payload type-tree) = int
22004     68/push 0/imm32/right:null
22005     68/push 0/imm32/right:null
22006     68/push 0/imm32/left:unused
22007     68/push 1/imm32/value:int
22008     68/push 1/imm32/is-atom?:true
22009     68/push 0x11/imm32/alloc-id:fake:payload
22010     89/<- %ecx 4/r32/esp
22011 $test-compare-eax-with-literal:initialize-var1:
22012     # var var1/ecx: (payload var)
22013     68/push 0/imm32/register
22014     68/push 0/imm32/register
22015     68/push 0/imm32/no-stack-offset
22016     68/push 1/imm32/block-depth
22017     51/push-ecx
22018     68/push 0x11/imm32/alloc-id:fake
22019     68/push 0/imm32/name
22020     68/push 0/imm32/name
22021     68/push 0x11/imm32/alloc-id:fake:payload
22022     89/<- %ecx 4/r32/esp
22023 $test-compare-eax-with-literal:initialize-var1-name:
22024     # var1->name = "var1"
22025     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22026     (copy-array Heap "var1" %eax)
22027 $test-compare-eax-with-literal:initialize-var1-register:
22028     # v->register = "eax"
22029     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
22030     (copy-array Heap "eax" %eax)
22031 $test-compare-eax-with-literal:initialize-literal-type:
22032     # var type/edx: (payload type-tree) = literal
22033     68/push 0/imm32/right:null
22034     68/push 0/imm32/right:null
22035     68/push 0/imm32/left:unused
22036     68/push 0/imm32/value:literal
22037     68/push 1/imm32/is-atom?:true
22038     68/push 0x11/imm32/alloc-id:fake:payload
22039     89/<- %edx 4/r32/esp
22040 $test-compare-eax-with-literal:initialize-literal:
22041     # var l/edx: (payload var)
22042     68/push 0/imm32/register
22043     68/push 0/imm32/register
22044     68/push 0/imm32/no-stack-offset
22045     68/push 1/imm32/block-depth
22046     52/push-edx
22047     68/push 0x11/imm32/alloc-id:fake
22048     68/push 0/imm32/name
22049     68/push 0/imm32/name
22050     68/push 0x11/imm32/alloc-id:fake:payload
22051     89/<- %edx 4/r32/esp
22052 $test-compare-eax-with-literal:initialize-literal-value:
22053     # l->name = "0x34"
22054     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
22055     (copy-array Heap "0x34" %eax)
22056 $test-compare-eax-with-literal:initialize-inouts:
22057     # var inouts/esi: (payload stmt-var) = [l]
22058     68/push 0/imm32/is-deref:false
22059     68/push 0/imm32/next
22060     68/push 0/imm32/next
22061     52/push-edx/l
22062     68/push 0x11/imm32/alloc-id:fake
22063     68/push 0x11/imm32/alloc-id:fake:payload
22064     89/<- %esi 4/r32/esp
22065     # var inouts = (handle stmt-var) = [var1, var2]
22066     68/push 0/imm32/is-deref:false
22067     56/push-esi/next
22068     68/push 0x11/imm32/alloc-id:fake
22069     51/push-ecx/var1
22070     68/push 0x11/imm32/alloc-id:fake
22071     68/push 0x11/imm32/alloc-id:fake:payload
22072     89/<- %esi 4/r32/esp
22073 $test-compare-eax-with-literal:initialize-stmt:
22074     # var stmt/esi: (addr statement)
22075     68/push 0/imm32/next
22076     68/push 0/imm32/next
22077     68/push 0/imm32/outputs
22078     68/push 0/imm32/outputs
22079     56/push-esi/inouts
22080     68/push 0x11/imm32/alloc-id:fake
22081     68/push 0/imm32/operation
22082     68/push 0/imm32/operation
22083     68/push 1/imm32/tag:stmt1
22084     89/<- %esi 4/r32/esp
22085 $test-compare-eax-with-literal:initialize-stmt-operation:
22086     # stmt->operation = "compare"
22087     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22088     (copy-array Heap "compare" %eax)
22089     # convert
22090     c7 0/subop/copy *Curr-block-depth 0/imm32
22091     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22092     (flush _test-output-buffered-file)
22093 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
22099     # check output
22100     (check-next-stream-line-equal _test-output-stream "3d/compare-eax-with 0x34/imm32" "F - test-compare-eax-with-literal")
22101     # . epilogue
22102     89/<- %esp 5/r32/ebp
22103     5d/pop-to-ebp
22104     c3/return
22105 
22106 test-compare-reg-with-literal:
22107     #   compare var1/ecx 0x34
22108     # =>
22109     #   81 7/subop/compare %ecx 0x34/imm32
22110     #
22111     # . prologue
22112     55/push-ebp
22113     89/<- %ebp 4/r32/esp
22114     # setup
22115     (clear-stream _test-output-stream)
22116     (clear-stream $_test-output-buffered-file->buffer)
22117 $test-compare-reg-with-literal:initialize-type:
22118     # var type/ecx: (payload type-tree) = int
22119     68/push 0/imm32/right:null
22120     68/push 0/imm32/right:null
22121     68/push 0/imm32/left:unused
22122     68/push 1/imm32/value:int
22123     68/push 1/imm32/is-atom?:true
22124     68/push 0x11/imm32/alloc-id:fake:payload
22125     89/<- %ecx 4/r32/esp
22126 $test-compare-reg-with-literal:initialize-var1:
22127     # var var1/ecx: (payload var)
22128     68/push 0/imm32/register
22129     68/push 0/imm32/register
22130     68/push 0/imm32/no-stack-offset
22131     68/push 1/imm32/block-depth
22132     51/push-ecx
22133     68/push 0x11/imm32/alloc-id:fake
22134     68/push 0/imm32/name
22135     68/push 0/imm32/name
22136     68/push 0x11/imm32/alloc-id:fake:payload
22137     89/<- %ecx 4/r32/esp
22138 $test-compare-reg-with-literal:initialize-var1-name:
22139     # var1->name = "var1"
22140     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22141     (copy-array Heap "var1" %eax)
22142 $test-compare-reg-with-literal:initialize-var1-register:
22143     # v->register = "ecx"
22144     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
22145     (copy-array Heap "ecx" %eax)
22146 $test-compare-reg-with-literal:initialize-literal-type:
22147     # var type/edx: (payload type-tree) = literal
22148     68/push 0/imm32/right:null
22149     68/push 0/imm32/right:null
22150     68/push 0/imm32/left:unused
22151     68/push 0/imm32/value:literal
22152     68/push 1/imm32/is-atom?:true
22153     68/push 0x11/imm32/alloc-id:fake:payload
22154     89/<- %edx 4/r32/esp
22155 $test-compare-reg-with-literal:initialize-literal:
22156     # var l/edx: (payload var)
22157     68/push 0/imm32/register
22158     68/push 0/imm32/register
22159     68/push 0/imm32/no-stack-offset
22160     68/push 1/imm32/block-depth
22161     52/push-edx
22162     68/push 0x11/imm32/alloc-id:fake
22163     68/push 0/imm32/name
22164     68/push 0/imm32/name
22165     68/push 0x11/imm32/alloc-id:fake:payload
22166     89/<- %edx 4/r32/esp
22167 $test-compare-reg-with-literal:initialize-literal-value:
22168     # l->name = "0x34"
22169     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
22170     (copy-array Heap "0x34" %eax)
22171 $test-compare-reg-with-literal:initialize-inouts:
22172     # var inouts/esi: (payload stmt-var) = [l]
22173     68/push 0/imm32/is-deref:false
22174     68/push 0/imm32/next
22175     68/push 0/imm32/next
22176     52/push-edx/l
22177     68/push 0x11/imm32/alloc-id:fake
22178     68/push 0x11/imm32/alloc-id:fake:payload
22179     89/<- %esi 4/r32/esp
22180     # var inouts = (handle stmt-var) = [var1, var2]
22181     68/push 0/imm32/is-deref:false
22182     56/push-esi/next
22183     68/push 0x11/imm32/alloc-id:fake
22184     51/push-ecx/var1
22185     68/push 0x11/imm32/alloc-id:fake
22186     68/push 0x11/imm32/alloc-id:fake:payload
22187     89/<- %esi 4/r32/esp
22188 $test-compare-reg-with-literal:initialize-stmt:
22189     # var stmt/esi: (addr statement)
22190     68/push 0/imm32/next
22191     68/push 0/imm32/next
22192     68/push 0/imm32/outputs
22193     68/push 0/imm32/outputs
22194     56/push-esi/inouts
22195     68/push 0x11/imm32/alloc-id:fake
22196     68/push 0/imm32/operation
22197     68/push 0/imm32/operation
22198     68/push 1/imm32/tag:stmt1
22199     89/<- %esi 4/r32/esp
22200 $test-compare-reg-with-literal:initialize-stmt-operation:
22201     # stmt->operation = "compare"
22202     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22203     (copy-array Heap "compare" %eax)
22204     # convert
22205     c7 0/subop/copy *Curr-block-depth 0/imm32
22206     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22207     (flush _test-output-buffered-file)
22208 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
22214     # check output
22215     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare %ecx 0x34/imm32" "F - test-compare-reg-with-literal")
22216     # . epilogue
22217     89/<- %esp 5/r32/ebp
22218     5d/pop-to-ebp
22219     c3/return
22220 
22221 test-emit-subx-stmt-function-call:
22222     # Call a function on a variable on the stack.
22223     #   f foo
22224     # =>
22225     #   (f *(ebp-8))
22226     # (Changing the function name supports overloading in general, but here it
22227     # just serves to help disambiguate things.)
22228     #
22229     # There's a variable on the var stack as follows:
22230     #   name: 'foo'
22231     #   type: int
22232     #   stack-offset: -8
22233     #
22234     # There's nothing in primitives.
22235     #
22236     # We don't perform any checking here on the type of 'f'.
22237     #
22238     # . prologue
22239     55/push-ebp
22240     89/<- %ebp 4/r32/esp
22241     # setup
22242     (clear-stream _test-output-stream)
22243     (clear-stream $_test-output-buffered-file->buffer)
22244 $test-emit-subx-function-call:initialize-type:
22245     # var type/ecx: (payload type-tree) = int
22246     68/push 0/imm32/right:null
22247     68/push 0/imm32/right:null
22248     68/push 0/imm32/left:unused
22249     68/push 1/imm32/value:int
22250     68/push 1/imm32/is-atom?:true
22251     68/push 0x11/imm32/alloc-id:fake:payload
22252     89/<- %ecx 4/r32/esp
22253 $test-emit-subx-function-call:initialize-var:
22254     # var var-foo/ecx: (payload var) = var(type)
22255     68/push 0/imm32/no-register
22256     68/push 0/imm32/no-register
22257     68/push -8/imm32/stack-offset
22258     68/push 1/imm32/block-depth
22259     51/push-ecx/type
22260     68/push 0x11/imm32/alloc-id:fake
22261     68/push 0/imm32/name
22262     68/push 0/imm32/name
22263     68/push 0x11/imm32/alloc-id:fake:payload
22264     89/<- %ecx 4/r32/esp
22265 $test-emit-subx-function-call:initialize-var-name:
22266     # var-foo->name = "foo"
22267     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22268     (copy-array Heap "foo" %eax)
22269 $test-emit-subx-function-call:initialize-stmt-var:
22270     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
22271     68/push 0/imm32/is-deref:false
22272     68/push 0/imm32/next
22273     68/push 0/imm32/next
22274     51/push-ecx/var-foo
22275     68/push 0x11/imm32/alloc-id:fake
22276     68/push 0x11/imm32/alloc-id:fake:payload
22277     89/<- %ebx 4/r32/esp
22278 $test-emit-subx-function-call:initialize-stmt:
22279     # var stmt/esi: (addr statement)
22280     68/push 0/imm32/no-outputs
22281     68/push 0/imm32/no-outputs
22282     53/push-ebx/inouts
22283     68/push 0x11/imm32/alloc-id:fake
22284     68/push 0/imm32/operation
22285     68/push 0/imm32/operation
22286     68/push 1/imm32/tag
22287     89/<- %esi 4/r32/esp
22288 $test-emit-subx-function-call:initialize-stmt-operation:
22289     # stmt->operation = "f"
22290     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22291     (copy-array Heap "f" %eax)
22292     # convert
22293     c7 0/subop/copy *Curr-block-depth 0/imm32
22294     (emit-subx-stmt _test-output-buffered-file %esi 0 Stderr 0)
22295     (flush _test-output-buffered-file)
22296 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
22302     # check output
22303     (check-next-stream-line-equal _test-output-stream "(f *(ebp+0xfffffff8))" "F - test-emit-subx-stmt-function-call")
22304     # . epilogue
22305     89/<- %esp 5/r32/ebp
22306     5d/pop-to-ebp
22307     c3/return
22308 
22309 test-emit-subx-stmt-function-call-with-literal-arg:
22310     # Call a function on a literal.
22311     #   f 0x34
22312     # =>
22313     #   (f2 0x34)
22314     #
22315     # . prologue
22316     55/push-ebp
22317     89/<- %ebp 4/r32/esp
22318     # setup
22319     (clear-stream _test-output-stream)
22320     (clear-stream $_test-output-buffered-file->buffer)
22321 $test-emit-subx-function-call-with-literal-arg:initialize-type:
22322     # var type/ecx: (payload type-tree) = int
22323     68/push 0/imm32/right:null
22324     68/push 0/imm32/right:null
22325     68/push 0/imm32/left:unused
22326     68/push 0/imm32/value:literal
22327     68/push 1/imm32/is-atom?:true
22328     68/push 0x11/imm32/alloc-id:fake:payload
22329     89/<- %ecx 4/r32/esp
22330 $test-emit-subx-function-call-with-literal-arg:initialize-var:
22331     # var var-foo/ecx: (payload var) = var(lit)
22332     68/push 0/imm32/no-register
22333     68/push 0/imm32/no-register
22334     68/push 0/imm32/no-stack-offset
22335     68/push 1/imm32/block-depth
22336     51/push-ecx/type
22337     68/push 0x11/imm32/alloc-id:fake
22338     68/push 0/imm32/name
22339     68/push 0/imm32/name
22340     68/push 0x11/imm32/alloc-id:fake:payload
22341     89/<- %ecx 4/r32/esp
22342 $test-emit-subx-function-call-with-literal-arg:initialize-var-name:
22343     # var-foo->name = "0x34"
22344     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22345     (copy-array Heap "0x34" %eax)
22346 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-var:
22347     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
22348     68/push 0/imm32/is-deref:false
22349     68/push 0/imm32/next
22350     68/push 0/imm32/next
22351     51/push-ecx/var-foo
22352     68/push 0x11/imm32/alloc-id:fake
22353     68/push 0x11/imm32/alloc-id:fake:payload
22354     89/<- %ebx 4/r32/esp
22355 $test-emit-subx-function-call-with-literal-arg:initialize-stmt:
22356     # var stmt/esi: (addr statement)
22357     68/push 0/imm32/no-outputs
22358     68/push 0/imm32/no-outputs
22359     53/push-ebx/inouts
22360     68/push 0x11/imm32/alloc-id:fake
22361     68/push 0/imm32/operation
22362     68/push 0/imm32/operation
22363     68/push 1/imm32/tag
22364     89/<- %esi 4/r32/esp
22365 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-operation:
22366     # stmt->operation = "f"
22367     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22368     (copy-array Heap "f" %eax)
22369     # convert
22370     c7 0/subop/copy *Curr-block-depth 0/imm32
22371     (emit-subx-stmt _test-output-buffered-file %esi 0 %ebx Stderr 0)
22372     (flush _test-output-buffered-file)
22373 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
22379     # check output
22380     (check-next-stream-line-equal _test-output-stream "(f 0x34)" "F - test-emit-subx-stmt-function-call-with-literal-arg")
22381     # . epilogue
22382     89/<- %esp 5/r32/ebp
22383     5d/pop-to-ebp
22384     c3/return
22385 
22386 emit-indent:  # out: (addr buffered-file), n: int
22387     # . prologue
22388     55/push-ebp
22389     89/<- %ebp 4/r32/esp
22390     # . save registers
22391     50/push-eax
22392     # var i/eax: int = n
22393     8b/-> *(ebp+0xc) 0/r32/eax
22394     {
22395       # if (i <= 0) break
22396       3d/compare-eax-with 0/imm32
22397       7e/jump-if-<= break/disp8
22398       (write-buffered *(ebp+8) "  ")
22399       48/decrement-eax
22400       eb/jump loop/disp8
22401     }
22402 $emit-indent:end:
22403     # . restore registers
22404     58/pop-to-eax
22405     # . epilogue
22406     89/<- %esp 5/r32/ebp
22407     5d/pop-to-ebp
22408     c3/return
22409 
22410 emit-subx-prologue:  # out: (addr buffered-file)
22411     # . prologue
22412     55/push-ebp
22413     89/<- %ebp 4/r32/esp
22414     #
22415     (write-buffered *(ebp+8) "  # . prologue\n")
22416     (write-buffered *(ebp+8) "  55/push-ebp\n")
22417     (write-buffered *(ebp+8) "  89/<- %ebp 4/r32/esp\n")
22418 $emit-subx-prologue:end:
22419     # . epilogue
22420     89/<- %esp 5/r32/ebp
22421     5d/pop-to-ebp
22422     c3/return
22423 
22424 emit-subx-epilogue:  # out: (addr buffered-file)
22425     # . prologue
22426     55/push-ebp
22427     89/<- %ebp 4/r32/esp
22428     #
22429     (write-buffered *(ebp+8) "  # . epilogue\n")
22430     (write-buffered *(ebp+8) "  89/<- %esp 5/r32/ebp\n")
22431     (write-buffered *(ebp+8) "  5d/pop-to-ebp\n")
22432     (write-buffered *(ebp+8) "  c3/return\n")
22433 $emit-subx-epilogue:end:
22434     # . epilogue
22435     89/<- %esp 5/r32/ebp
22436     5d/pop-to-ebp
22437     c3/return