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   0/imm32  # 0 reserved for literals; value is just the name
  397            # Not to be used directly, so we don't include a name here.
  398   "int"/imm32  # 1
  399   "addr"/imm32  # 2
  400   "array"/imm32  # 3
  401   "handle"/imm32  # 4
  402   "boolean"/imm32  # 5
  403   0/imm32  # 6 reserved for constants; they're like literals, but value is an int in Var-offset
  404            # Not to be used directly, so we don't include a name here.
  405   "offset"/imm32  # 7: (offset T) is guaranteed to be a 32-bit multiple of size-of(T)
  406   # 0x20
  407   "byte"/imm32  # 8
  408   0/imm32  # 9 reserved for array-capacity; value is in Type-tree-size.
  409            # Not to be used directly, so we don't include a name here.
  410   0/imm32  # 10 reserved for type parameters; value is (address array byte) in Type-tree-value2.
  411            # Not to be used directly, so we don't include a name here.
  412   # some SubX types deliberately left undefined in Mu; they can only be operated on using SubX primitives
  413   "stream"/imm32  # 11
  414   "slice"/imm32  # 12
  415   "code-point"/imm32  # 13; smallest scannable unit from a text stream
  416   "grapheme"/imm32  # 14; smallest printable unit; will eventually be composed of multiple code-points, but currently corresponds 1:1
  417                     # only 4-byte graphemes in utf-8 are currently supported;
  418                     # unclear how we should deal with larger clusters.
  419   # Keep Primitive-type-ids in sync if you add types here.
  420                                                           0/imm32
  421   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  422   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  423   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  424   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  425   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  426   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  427 
  428 Primitive-type-ids:  # (addr int)
  429   0x34
  430 
  431 # == Type definitions
  432 # Program->types contains some typeinfo for each type definition.
  433 # Types contain vars with types, but can't specify registers.
  434 Typeinfo-id:  # type-id
  435   0/imm32
  436 Typeinfo-fields:  # (handle table (handle array byte) (handle typeinfo-entry))
  437   4/imm32
  438 # Total size must be >= 0
  439 # During parsing it may take on two additional values:
  440 #   -2: not yet initialized
  441 #   -1: in process of being computed
  442 # See populate-mu-type-sizes for details.
  443 Typeinfo-total-size-in-bytes:  # int
  444   0xc/imm32
  445 Typeinfo-next:  # (handle typeinfo)
  446   0x10/imm32
  447 Typeinfo-size:  # (addr int)
  448   0x18/imm32
  449 
  450 # Each entry in the typeinfo->fields table has a pointer to a string and a
  451 # pointer to a typeinfo-entry.
  452 Typeinfo-fields-row-size:  # (addr int)
  453   0x10/imm32
  454 
  455 # typeinfo-entry objects have information about a field in a single record type
  456 #
  457 # each field of a type is represented using two var's:
  458 #   1. the input var: expected type of the field; convenient for creating using parse-var-with-type
  459 #   2. the output var: a constant containing the byte offset; convenient for code-generation
  460 # computing the output happens after parsing; in the meantime we preserve the
  461 # order of fields in the 'index' field.
  462 Typeinfo-entry-input-var:  # (handle var)
  463   0/imm32
  464 Typeinfo-entry-index:  # int
  465   8/imm32
  466 Typeinfo-entry-output-var:  # (handle var)
  467   0xc/imm32
  468 Typeinfo-entry-size:  # (addr int)
  469   0x14/imm32
  470 
  471 == code
  472 
  473 Entry:
  474     # . prologue
  475     89/<- %ebp 4/r32/esp
  476     (new-segment *Heap-size Heap)
  477     # if (argv[1] == "test') run-tests()
  478     {
  479       # if (argc <= 1) break
  480       81 7/subop/compare *ebp 1/imm32
  481       7e/jump-if-<= break/disp8
  482       # if (argv[1] != "test") break
  483       (kernel-string-equal? *(ebp+8) "test")  # => eax
  484       3d/compare-eax-and 0/imm32/false
  485       74/jump-if-= break/disp8
  486       #
  487       (run-tests)
  488       # syscall(exit, *Num-test-failures)
  489       8b/-> *Num-test-failures 3/r32/ebx
  490       eb/jump $mu-main:end/disp8
  491     }
  492     # otherwise convert Stdin
  493     (convert-mu Stdin Stdout Stderr 0)
  494     (flush Stdout)
  495     # syscall(exit, 0)
  496     bb/copy-to-ebx 0/imm32
  497 $mu-main:end:
  498     e8/call syscall_exit/disp32
  499 
  500 convert-mu:  # in: (addr buffered-file), out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
  501     # . prologue
  502     55/push-ebp
  503     89/<- %ebp 4/r32/esp
  504     # . save registers
  505     50/push-eax
  506     # initialize global data structures
  507     c7 0/subop/copy *Next-block-index 1/imm32
  508     8b/-> *Primitive-type-ids 0/r32/eax
  509     89/<- *Type-id 0/r32/eax  # stream-write
  510     c7 0/subop/copy *_Program-functions 0/imm32
  511     c7 0/subop/copy *_Program-functions->payload 0/imm32
  512     c7 0/subop/copy *_Program-types 0/imm32
  513     c7 0/subop/copy *_Program-types->payload 0/imm32
  514     c7 0/subop/copy *_Program-signatures 0/imm32
  515     c7 0/subop/copy *_Program-signatures->payload 0/imm32
  516     #
  517     (parse-mu *(ebp+8) *(ebp+0x10) *(ebp+0x14))
  518     (populate-mu-type-sizes *(ebp+0x10) *(ebp+0x14))
  519 #?     (dump-typeinfos "=== typeinfos\n")
  520     (check-mu-types *(ebp+0x10) *(ebp+0x14))
  521     (emit-subx *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
  522 $convert-mu:end:
  523     # . restore registers
  524     58/pop-to-eax
  525     # . epilogue
  526     89/<- %esp 5/r32/ebp
  527     5d/pop-to-ebp
  528     c3/return
  529 
  530 test-convert-empty-input:
  531     # empty input => empty output
  532     # . prologue
  533     55/push-ebp
  534     89/<- %ebp 4/r32/esp
  535     # setup
  536     (clear-stream _test-input-stream)
  537     (clear-stream $_test-input-buffered-file->buffer)
  538     (clear-stream _test-output-stream)
  539     (clear-stream $_test-output-buffered-file->buffer)
  540     #
  541     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  542     (flush _test-output-buffered-file)
  543     (check-stream-equal _test-output-stream "" "F - test-convert-empty-input")
  544     # . epilogue
  545     89/<- %esp 5/r32/ebp
  546     5d/pop-to-ebp
  547     c3/return
  548 
  549 test-convert-function-skeleton:
  550     # . prologue
  551     55/push-ebp
  552     89/<- %ebp 4/r32/esp
  553     # setup
  554     (clear-stream _test-input-stream)
  555     (clear-stream $_test-input-buffered-file->buffer)
  556     (clear-stream _test-output-stream)
  557     (clear-stream $_test-output-buffered-file->buffer)
  558     #
  559     (write _test-input-stream "fn foo {\n")
  560     (write _test-input-stream "}\n")
  561     # convert
  562     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  563     (flush _test-output-buffered-file)
  564 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  570     # check output
  571     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-skeleton/0")
  572     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-skeleton/1")
  573     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-skeleton/2")
  574     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-skeleton/3")
  575     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-skeleton/4")
  576     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-skeleton/5")
  577     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-skeleton/6")
  578     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-skeleton/7")
  579     # . epilogue
  580     89/<- %esp 5/r32/ebp
  581     5d/pop-to-ebp
  582     c3/return
  583 
  584 test-convert-multiple-function-skeletons:
  585     # . prologue
  586     55/push-ebp
  587     89/<- %ebp 4/r32/esp
  588     # setup
  589     (clear-stream _test-input-stream)
  590     (clear-stream $_test-input-buffered-file->buffer)
  591     (clear-stream _test-output-stream)
  592     (clear-stream $_test-output-buffered-file->buffer)
  593     #
  594     (write _test-input-stream "fn foo {\n")
  595     (write _test-input-stream "}\n")
  596     (write _test-input-stream "fn bar {\n")
  597     (write _test-input-stream "}\n")
  598     # convert
  599     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  600     (flush _test-output-buffered-file)
  601 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  607     # check first function
  608     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-multiple-function-skeletons/0")
  609     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/1")
  610     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/2")
  611     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/3")
  612     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/4")
  613     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/5")
  614     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/6")
  615     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/7")
  616     # check second function
  617     (check-next-stream-line-equal _test-output-stream "bar:"                    "F - test-convert-multiple-function-skeletons/10")
  618     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/11")
  619     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/12")
  620     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/13")
  621     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/14")
  622     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/15")
  623     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/16")
  624     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/17")
  625     # . epilogue
  626     89/<- %esp 5/r32/ebp
  627     5d/pop-to-ebp
  628     c3/return
  629 
  630 test-convert-function-with-arg:
  631     # . prologue
  632     55/push-ebp
  633     89/<- %ebp 4/r32/esp
  634     # setup
  635     (clear-stream _test-input-stream)
  636     (clear-stream $_test-input-buffered-file->buffer)
  637     (clear-stream _test-output-stream)
  638     (clear-stream $_test-output-buffered-file->buffer)
  639     #
  640     (write _test-input-stream "fn foo n: int {\n")
  641     (write _test-input-stream "}\n")
  642     # convert
  643     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  644     (flush _test-output-buffered-file)
  645 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  651     # check output
  652     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg/0")
  653     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg/1")
  654     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg/2")
  655     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg/3")
  656     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg/4")
  657     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg/5")
  658     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg/6")
  659     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg/7")
  660     # . epilogue
  661     89/<- %esp 5/r32/ebp
  662     5d/pop-to-ebp
  663     c3/return
  664 
  665 test-convert-function-with-arg-and-body:
  666     # . prologue
  667     55/push-ebp
  668     89/<- %ebp 4/r32/esp
  669     # setup
  670     (clear-stream _test-input-stream)
  671     (clear-stream $_test-input-buffered-file->buffer)
  672     (clear-stream _test-output-stream)
  673     (clear-stream $_test-output-buffered-file->buffer)
  674     #
  675     (write _test-input-stream "fn foo n: int {\n")
  676     (write _test-input-stream "  increment n\n")
  677     (write _test-input-stream "}\n")
  678     # convert
  679     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  680     (flush _test-output-buffered-file)
  681 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  687     # check output
  688     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg-and-body/0")
  689     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg-and-body/1")
  690     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg-and-body/2")
  691     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg-and-body/3")
  692     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-arg-and-body/4")
  693     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-arg-and-body/5")
  694     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-arg-and-body/6")
  695     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-arg-and-body/7")
  696     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-arg-and-body/8")
  697     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg-and-body/9")
  698     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg-and-body/10")
  699     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg-and-body/11")
  700     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg-and-body/12")
  701     # . epilogue
  702     89/<- %esp 5/r32/ebp
  703     5d/pop-to-ebp
  704     c3/return
  705 
  706 test-convert-function-distinguishes-args:
  707     # . prologue
  708     55/push-ebp
  709     89/<- %ebp 4/r32/esp
  710     # setup
  711     (clear-stream _test-input-stream)
  712     (clear-stream $_test-input-buffered-file->buffer)
  713     (clear-stream _test-output-stream)
  714     (clear-stream $_test-output-buffered-file->buffer)
  715     #
  716     (write _test-input-stream "fn foo a: int, b: int {\n")
  717     (write _test-input-stream "  increment b\n")
  718     (write _test-input-stream "}\n")
  719     # convert
  720     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  721     (flush _test-output-buffered-file)
  722 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  728     # check output
  729     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-distinguishes-args/0")
  730     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-distinguishes-args/1")
  731     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-distinguishes-args/2")
  732     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-distinguishes-args/3")
  733     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-distinguishes-args/4")
  734     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-distinguishes-args/5")
  735     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x0000000c)"  "F - test-convert-function-distinguishes-args/6")
  736     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-distinguishes-args/7")
  737     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-distinguishes-args/8")
  738     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-distinguishes-args/9")
  739     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-distinguishes-args/10")
  740     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-distinguishes-args/11")
  741     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-distinguishes-args/12")
  742     # . epilogue
  743     89/<- %esp 5/r32/ebp
  744     5d/pop-to-ebp
  745     c3/return
  746 
  747 test-convert-function-returns-result:
  748     # . prologue
  749     55/push-ebp
  750     89/<- %ebp 4/r32/esp
  751     # setup
  752     (clear-stream _test-input-stream)
  753     (clear-stream $_test-input-buffered-file->buffer)
  754     (clear-stream _test-output-stream)
  755     (clear-stream $_test-output-buffered-file->buffer)
  756     #
  757     (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n")
  758     (write _test-input-stream "  result <- copy a\n")
  759     (write _test-input-stream "  result <- increment\n")
  760     (write _test-input-stream "}\n")
  761     # convert
  762     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  763     (flush _test-output-buffered-file)
  764 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  770     # check output
  771     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-returns-result/0")
  772     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-returns-result/1")
  773     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-returns-result/2")
  774     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-returns-result/3")
  775     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-returns-result/4")
  776     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-returns-result/5")
  777     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-returns-result/6")
  778     (check-next-stream-line-equal _test-output-stream "    40/increment-eax"    "F - test-convert-function-returns-result/7")
  779     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-returns-result/8")
  780     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-returns-result/9")
  781     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-returns-result/10")
  782     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-returns-result/11")
  783     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-returns-result/12")
  784     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-returns-result/13")
  785     # . epilogue
  786     89/<- %esp 5/r32/ebp
  787     5d/pop-to-ebp
  788     c3/return
  789 
  790 test-convert-function-with-literal-arg:
  791     # . prologue
  792     55/push-ebp
  793     89/<- %ebp 4/r32/esp
  794     # setup
  795     (clear-stream _test-input-stream)
  796     (clear-stream $_test-input-buffered-file->buffer)
  797     (clear-stream _test-output-stream)
  798     (clear-stream $_test-output-buffered-file->buffer)
  799     #
  800     (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n")
  801     (write _test-input-stream "  result <- copy a\n")
  802     (write _test-input-stream "  result <- add 1\n")
  803     (write _test-input-stream "}\n")
  804     # convert
  805     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  806     (flush _test-output-buffered-file)
  807 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  813     # check output
  814     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg/0")
  815     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg/1")
  816     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg/2")
  817     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg/3")
  818     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg/4")
  819     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg/5")
  820     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-with-literal-arg/6")
  821     (check-next-stream-line-equal _test-output-stream "    05/add-to-eax 1/imm32"  "F - test-convert-function-with-literal-arg/7")
  822     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg/8")
  823     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg/9")
  824     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg/10")
  825     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg/11")
  826     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg/12")
  827     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg/13")
  828     # . epilogue
  829     89/<- %esp 5/r32/ebp
  830     5d/pop-to-ebp
  831     c3/return
  832 
  833 test-convert-function-with-literal-arg-2:
  834     # . prologue
  835     55/push-ebp
  836     89/<- %ebp 4/r32/esp
  837     # setup
  838     (clear-stream _test-input-stream)
  839     (clear-stream $_test-input-buffered-file->buffer)
  840     (clear-stream _test-output-stream)
  841     (clear-stream $_test-output-buffered-file->buffer)
  842     #
  843     (write _test-input-stream "fn foo a: int, b: int -> result/ebx: int {\n")
  844     (write _test-input-stream "  result <- copy a\n")
  845     (write _test-input-stream "  result <- add 1\n")
  846     (write _test-input-stream "}\n")
  847     # convert
  848     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  849     (flush _test-output-buffered-file)
  850 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  856     # check output
  857     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg-2/0")
  858     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg-2/1")
  859     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg-2/2")
  860     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg-2/3")
  861     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg-2/4")
  862     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg-2/5")
  863     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-with-literal-arg-2/6")
  864     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %ebx 1/imm32"  "F - test-convert-function-with-literal-arg-2/7")
  865     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg-2/8")
  866     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg-2/9")
  867     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg-2/10")
  868     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg-2/11")
  869     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg-2/12")
  870     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg-2/13")
  871     # . epilogue
  872     89/<- %esp 5/r32/ebp
  873     5d/pop-to-ebp
  874     c3/return
  875 
  876 test-convert-function-call-with-literal-arg:
  877     # . prologue
  878     55/push-ebp
  879     89/<- %ebp 4/r32/esp
  880     # setup
  881     (clear-stream _test-input-stream)
  882     (clear-stream $_test-input-buffered-file->buffer)
  883     (clear-stream _test-output-stream)
  884     (clear-stream $_test-output-buffered-file->buffer)
  885     #
  886     (write _test-input-stream "fn main -> result/ebx: int {\n")
  887     (write _test-input-stream "  result <- do-add 3 4\n")
  888     (write _test-input-stream "}\n")
  889     (write _test-input-stream "fn do-add a: int, b: int -> result/ebx: int {\n")
  890     (write _test-input-stream "  result <- copy a\n")
  891     (write _test-input-stream "  result <- add b\n")
  892     (write _test-input-stream "}\n")
  893     # convert
  894     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  895     (flush _test-output-buffered-file)
  896 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  902     # check output
  903     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call-with-literal-arg/0")
  904     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/1")
  905     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/2")
  906     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/3")
  907     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/4")
  908     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call-with-literal-arg/5")
  909     (check-next-stream-line-equal _test-output-stream "    (do-add 3 4)"        "F - test-convert-function-call-with-literal-arg/6")
  910     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/7")
  911     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-literal-arg/8")
  912     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/9")
  913     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/10")
  914     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/11")
  915     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/12")
  916     (check-next-stream-line-equal _test-output-stream "do-add:"                 "F - test-convert-function-call-with-literal-arg/13")
  917     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/14")
  918     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/15")
  919     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/16")
  920     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/17")
  921     (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:loop:"  "F - test-convert-function-call-with-literal-arg/18")
  922     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-call-with-literal-arg/19")
  923     (check-next-stream-line-equal _test-output-stream "    03/add *(ebp+0x0000000c) 0x00000003/r32"  "F - test-convert-function-call-with-literal-arg/20")
  924     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/21")
  925     (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:break:"  "F - test-convert-function-call-with-literal-arg/22")
  926     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/23")
  927     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/24")
  928     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/25")
  929     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/26")
  930     # . epilogue
  931     89/<- %esp 5/r32/ebp
  932     5d/pop-to-ebp
  933     c3/return
  934 
  935 test-convert-function-call-with-signature:
  936     # . prologue
  937     55/push-ebp
  938     89/<- %ebp 4/r32/esp
  939     # setup
  940     (clear-stream _test-input-stream)
  941     (clear-stream $_test-input-buffered-file->buffer)
  942     (clear-stream _test-output-stream)
  943     (clear-stream $_test-output-buffered-file->buffer)
  944     #
  945     (write _test-input-stream "fn main -> result/ebx: int {\n")
  946     (write _test-input-stream "  result <- do-add 3 4\n")
  947     (write _test-input-stream "}\n")
  948     (write _test-input-stream "sig do-add a: int, b: int -> result/ebx: int\n")
  949     # convert
  950     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  951     (flush _test-output-buffered-file)
  952 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  958     # check output
  959     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call-with-signature/0")
  960     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-signature/1")
  961     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-signature/2")
  962     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-signature/3")
  963     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-signature/4")
  964     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call-with-signature/5")
  965     (check-next-stream-line-equal _test-output-stream "    (do-add 3 4)"        "F - test-convert-function-call-with-signature/6")
  966     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-signature/7")
  967     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-signature/8")
  968     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-signature/9")
  969     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-signature/10")
  970     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-signature/11")
  971     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-signature/12")
  972     # . epilogue
  973     89/<- %esp 5/r32/ebp
  974     5d/pop-to-ebp
  975     c3/return
  976 
  977 test-convert-function-with-local-var-in-mem:
  978     # . prologue
  979     55/push-ebp
  980     89/<- %ebp 4/r32/esp
  981     # setup
  982     (clear-stream _test-input-stream)
  983     (clear-stream $_test-input-buffered-file->buffer)
  984     (clear-stream _test-output-stream)
  985     (clear-stream $_test-output-buffered-file->buffer)
  986     #
  987     (write _test-input-stream "fn foo {\n")
  988     (write _test-input-stream "  var x: int\n")
  989     (write _test-input-stream "  increment x\n")
  990     (write _test-input-stream "}\n")
  991     # convert
  992     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  993     (flush _test-output-buffered-file)
  994 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1000     # check output
 1001     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-mem/0")
 1002     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-mem/1")
 1003     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-mem/2")
 1004     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-mem/3")
 1005     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-mem/4")
 1006     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-mem/5")
 1007     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-in-mem/6")
 1008     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-mem/7")
 1009     (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")
 1010     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-mem/9")
 1011     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-mem/10")
 1012     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-mem/11")
 1013     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-mem/12")
 1014     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-mem/13")
 1015     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-mem/14")
 1016     # . epilogue
 1017     89/<- %esp 5/r32/ebp
 1018     5d/pop-to-ebp
 1019     c3/return
 1020 
 1021 test-convert-invalid-literal:
 1022     # . prologue
 1023     55/push-ebp
 1024     89/<- %ebp 4/r32/esp
 1025     # setup
 1026     (clear-stream _test-input-stream)
 1027     (clear-stream $_test-input-buffered-file->buffer)
 1028     (clear-stream _test-output-stream)
 1029     (clear-stream $_test-output-buffered-file->buffer)
 1030     (clear-stream _test-error-stream)
 1031     (clear-stream $_test-error-buffered-file->buffer)
 1032     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1033     68/push 0/imm32
 1034     68/push 0/imm32
 1035     89/<- %edx 4/r32/esp
 1036     (tailor-exit-descriptor %edx 0x10)
 1037     #
 1038     (write _test-input-stream "fn foo {\n")
 1039     (write _test-input-stream "  increment 1n\n")
 1040     (write _test-input-stream "}\n")
 1041     # convert
 1042     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1043     # registers except esp clobbered at this point
 1044     # restore ed
 1045     89/<- %edx 4/r32/esp
 1046     (flush _test-output-buffered-file)
 1047     (flush _test-error-buffered-file)
 1048 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1054     # check output
 1055     (check-stream-equal _test-output-stream  ""  "F - test-convert-invalid-literal: output should be empty")
 1056     (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")
 1057     # check that stop(1) was called
 1058     (check-ints-equal *(edx+4) 2 "F - test-convert-invalid-literal: exit status")
 1059     # don't restore from ebp
 1060     81 0/subop/add %esp 8/imm32
 1061     # . epilogue
 1062     5d/pop-to-ebp
 1063     c3/return
 1064 
 1065 test-local-var-in-mem-has-no-initializer:
 1066     # . prologue
 1067     55/push-ebp
 1068     89/<- %ebp 4/r32/esp
 1069     # setup
 1070     (clear-stream _test-input-stream)
 1071     (clear-stream $_test-input-buffered-file->buffer)
 1072     (clear-stream _test-output-stream)
 1073     (clear-stream $_test-output-buffered-file->buffer)
 1074     (clear-stream _test-error-stream)
 1075     (clear-stream $_test-error-buffered-file->buffer)
 1076     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1077     68/push 0/imm32
 1078     68/push 0/imm32
 1079     89/<- %edx 4/r32/esp
 1080     (tailor-exit-descriptor %edx 0x10)
 1081     #
 1082     (write _test-input-stream "fn foo {\n")
 1083     (write _test-input-stream "  var x: int <- copy 0\n")
 1084     (write _test-input-stream "  increment x\n")
 1085     (write _test-input-stream "}\n")
 1086     # convert
 1087     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1088     # registers except esp clobbered at this point
 1089     # restore ed
 1090     89/<- %edx 4/r32/esp
 1091     (flush _test-output-buffered-file)
 1092     (flush _test-error-buffered-file)
 1093 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1099     # check output
 1100     (check-stream-equal _test-output-stream  ""  "F - test-var-in-mem-has-no-initializer: output should be empty")
 1101     (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")
 1102     # check that stop(1) was called
 1103     (check-ints-equal *(edx+4) 2 "F - test-var-in-mem-has-no-initializer: exit status")
 1104     # don't restore from ebp
 1105     81 0/subop/add %esp 8/imm32
 1106     # . epilogue
 1107     5d/pop-to-ebp
 1108     c3/return
 1109 
 1110 test-convert-function-with-local-var-with-compound-type-in-mem:
 1111     # . prologue
 1112     55/push-ebp
 1113     89/<- %ebp 4/r32/esp
 1114     # setup
 1115     (clear-stream _test-input-stream)
 1116     (clear-stream $_test-input-buffered-file->buffer)
 1117     (clear-stream _test-output-stream)
 1118     (clear-stream $_test-output-buffered-file->buffer)
 1119     #
 1120     (write _test-input-stream "fn foo {\n")
 1121     (write _test-input-stream "  var x: (addr int)\n")
 1122     (write _test-input-stream "  copy-to x, 0\n")
 1123     (write _test-input-stream "}\n")
 1124     # convert
 1125     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1126     (flush _test-output-buffered-file)
 1127 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1133     # check output
 1134     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-compound-type-in-mem/0")
 1135     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/1")
 1136     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-compound-type-in-mem/2")
 1137     (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")
 1138     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/4")
 1139     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-compound-type-in-mem/5")
 1140     (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")
 1141     (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")
 1142     (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")
 1143     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/9")
 1144     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/10")
 1145     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/11")
 1146     (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")
 1147     (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")
 1148     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-compound-type-in-mem/14")
 1149     # . epilogue
 1150     89/<- %esp 5/r32/ebp
 1151     5d/pop-to-ebp
 1152     c3/return
 1153 
 1154 test-convert-function-with-local-var-in-reg:
 1155     # . prologue
 1156     55/push-ebp
 1157     89/<- %ebp 4/r32/esp
 1158     # setup
 1159     (clear-stream _test-input-stream)
 1160     (clear-stream $_test-input-buffered-file->buffer)
 1161     (clear-stream _test-output-stream)
 1162     (clear-stream $_test-output-buffered-file->buffer)
 1163     #
 1164     (write _test-input-stream "fn foo {\n")
 1165     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1166     (write _test-input-stream "  x <- increment\n")
 1167     (write _test-input-stream "}\n")
 1168     # convert
 1169     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1170     (flush _test-output-buffered-file)
 1171 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1177     # check output
 1178     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-reg/0")
 1179     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-reg/1")
 1180     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-reg/2")
 1181     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-reg/3")
 1182     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-reg/4")
 1183     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-reg/5")
 1184     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-in-reg/6")
 1185     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-convert-function-with-local-var-in-reg/7")
 1186     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-local-var-in-reg/8")
 1187     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-in-reg/9")
 1188     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-reg/10")
 1189     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-reg/11")
 1190     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-reg/12")
 1191     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-reg/13")
 1192     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-reg/14")
 1193     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-reg/15")
 1194     # . epilogue
 1195     89/<- %esp 5/r32/ebp
 1196     5d/pop-to-ebp
 1197     c3/return
 1198 
 1199 test-convert-function-with-allocate:
 1200     # . prologue
 1201     55/push-ebp
 1202     89/<- %ebp 4/r32/esp
 1203     # setup
 1204     (clear-stream _test-input-stream)
 1205     (clear-stream $_test-input-buffered-file->buffer)
 1206     (clear-stream _test-output-stream)
 1207     (clear-stream $_test-output-buffered-file->buffer)
 1208     #
 1209     (write _test-input-stream "fn foo {\n")
 1210     (write _test-input-stream "  var x/ecx: (addr handle int) <- copy 0\n")
 1211     (write _test-input-stream "  allocate x\n")
 1212     (write _test-input-stream "}\n")
 1213     # convert
 1214     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1215     (flush _test-output-buffered-file)
 1216 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1222     # check output
 1223     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-allocate/0")
 1224     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-allocate/1")
 1225     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-allocate/2")
 1226     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-allocate/3")
 1227     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-allocate/4")
 1228     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-allocate/5")
 1229     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-allocate/6")
 1230     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-allocate/7")
 1231     (check-next-stream-line-equal _test-output-stream "    (allocate Heap 0x00000004 %ecx)"  "F - test-convert-function-with-allocate/8")  # 4 = size-of(int)
 1232     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-allocate/9")
 1233     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-allocate/10")
 1234     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-allocate/11")
 1235     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-allocate/12")
 1236     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-allocate/13")
 1237     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-allocate/14")
 1238     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-allocate/15")
 1239     # . epilogue
 1240     89/<- %esp 5/r32/ebp
 1241     5d/pop-to-ebp
 1242     c3/return
 1243 
 1244 test-initializer-in-hex:
 1245     # . prologue
 1246     55/push-ebp
 1247     89/<- %ebp 4/r32/esp
 1248     # setup
 1249     (clear-stream _test-input-stream)
 1250     (clear-stream $_test-input-buffered-file->buffer)
 1251     (clear-stream _test-output-stream)
 1252     (clear-stream $_test-output-buffered-file->buffer)
 1253     (clear-stream _test-error-stream)
 1254     (clear-stream $_test-error-buffered-file->buffer)
 1255     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1256     68/push 0/imm32
 1257     68/push 0/imm32
 1258     89/<- %edx 4/r32/esp
 1259     (tailor-exit-descriptor %edx 0x10)
 1260     #
 1261     (write _test-input-stream "fn foo {\n")
 1262     (write _test-input-stream "  var x/ecx: int <- copy 10\n")
 1263     (write _test-input-stream "}\n")
 1264     # convert
 1265     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1266     # registers except esp clobbered at this point
 1267     # restore ed
 1268     89/<- %edx 4/r32/esp
 1269     (flush _test-output-buffered-file)
 1270     (flush _test-error-buffered-file)
 1271 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1277     # check output
 1278     (check-stream-equal _test-output-stream  ""  "F - test-initializer-in-hex: output should be empty")
 1279     (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")
 1280     # check that stop(1) was called
 1281     (check-ints-equal *(edx+4) 2 "F - test-initializer-in-hex: exit status")
 1282     # don't restore from ebp
 1283     81 0/subop/add %esp 8/imm32
 1284     # . epilogue
 1285     5d/pop-to-ebp
 1286     c3/return
 1287 
 1288 test-convert-function-with-second-local-var-in-same-reg:
 1289     # . prologue
 1290     55/push-ebp
 1291     89/<- %ebp 4/r32/esp
 1292     # setup
 1293     (clear-stream _test-input-stream)
 1294     (clear-stream $_test-input-buffered-file->buffer)
 1295     (clear-stream _test-output-stream)
 1296     (clear-stream $_test-output-buffered-file->buffer)
 1297     #
 1298     (write _test-input-stream "fn foo {\n")
 1299     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1300     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1301     (write _test-input-stream "  y <- increment\n")
 1302     (write _test-input-stream "}\n")
 1303     # convert
 1304     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1305     (flush _test-output-buffered-file)
 1306 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1312     # check output
 1313     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-second-local-var-in-same-reg/0")
 1314     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-second-local-var-in-same-reg/1")
 1315     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-second-local-var-in-same-reg/2")
 1316     (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")
 1317     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-second-local-var-in-same-reg/4")
 1318     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-second-local-var-in-same-reg/5")
 1319     (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")
 1320     (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")
 1321     (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")
 1322     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-second-local-var-in-same-reg/9")
 1323     (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")
 1324     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-second-local-var-in-same-reg/11")
 1325     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-second-local-var-in-same-reg/12")
 1326     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-second-local-var-in-same-reg/13")
 1327     (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")
 1328     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-second-local-var-in-same-reg/15")
 1329     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-second-local-var-in-same-reg/16")
 1330     # . epilogue
 1331     89/<- %esp 5/r32/ebp
 1332     5d/pop-to-ebp
 1333     c3/return
 1334 
 1335 test-read-clobbered-reg-var:
 1336     # . prologue
 1337     55/push-ebp
 1338     89/<- %ebp 4/r32/esp
 1339     # setup
 1340     (clear-stream _test-input-stream)
 1341     (clear-stream $_test-input-buffered-file->buffer)
 1342     (clear-stream _test-output-stream)
 1343     (clear-stream $_test-output-buffered-file->buffer)
 1344     (clear-stream _test-error-stream)
 1345     (clear-stream $_test-error-buffered-file->buffer)
 1346     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)  # bytes of args in call to convert-mu
 1347     68/push 0/imm32
 1348     68/push 0/imm32
 1349     89/<- %edx 4/r32/esp
 1350     (tailor-exit-descriptor %edx 0x10)
 1351     #
 1352     (write _test-input-stream "fn foo {\n")
 1353     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1354     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1355     (write _test-input-stream "  x <- increment\n")
 1356     (write _test-input-stream "}\n")
 1357     # convert
 1358     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1359     # registers except esp clobbered at this point
 1360     # restore ed
 1361     89/<- %edx 4/r32/esp
 1362     (flush _test-output-buffered-file)
 1363     (flush _test-error-buffered-file)
 1364 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1370     # check output
 1371     (check-stream-equal _test-output-stream  ""  "F - test-read-clobbered-reg-var: output should be empty")
 1372     (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")
 1373     # check that stop(1) was called
 1374     (check-ints-equal *(edx+4) 2 "F - test-read-clobbered-reg-var: exit status")
 1375     # don't restore from ebp
 1376     81 0/subop/add %esp 8/imm32
 1377     # . epilogue
 1378     5d/pop-to-ebp
 1379     c3/return
 1380 
 1381 test-convert-function-call:
 1382     # . prologue
 1383     55/push-ebp
 1384     89/<- %ebp 4/r32/esp
 1385     # setup
 1386     (clear-stream _test-input-stream)
 1387     (clear-stream $_test-input-buffered-file->buffer)
 1388     (clear-stream _test-output-stream)
 1389     (clear-stream $_test-output-buffered-file->buffer)
 1390     #
 1391     (write _test-input-stream "fn main -> result/ebx: int {\n")
 1392     (write _test-input-stream "  result <- foo\n")
 1393     (write _test-input-stream "}\n")
 1394     (write _test-input-stream "fn foo -> result/ebx: int {\n")
 1395     (write _test-input-stream "  result <- copy 3\n")
 1396     (write _test-input-stream "}\n")
 1397     # convert
 1398     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1399     (flush _test-output-buffered-file)
 1400 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1406     # check output
 1407     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call/0")
 1408     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call/1")
 1409     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call/2")
 1410     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call/3")
 1411     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call/4")
 1412     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call/5")
 1413     (check-next-stream-line-equal _test-output-stream "    (foo)"               "F - test-convert-function-call/6")
 1414     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call/7")
 1415     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call/8")
 1416     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call/9")
 1417     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call/10")
 1418     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call/11")
 1419     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call/12")
 1420     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call/13")
 1421     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call/14")
 1422     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call/15")
 1423     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call/16")
 1424     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call/17")
 1425     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"  "F - test-convert-function-call/18")
 1426     (check-next-stream-line-equal _test-output-stream "    bb/copy-to-ebx 3/imm32"  "F - test-convert-function-call/19")
 1427     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call/20")
 1428     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-call/21")
 1429     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call/22")
 1430     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call/23")
 1431     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call/24")
 1432     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call/25")
 1433     # . epilogue
 1434     89/<- %esp 5/r32/ebp
 1435     5d/pop-to-ebp
 1436     c3/return
 1437 
 1438 test-convert-function-call-with-inout-with-compound-type:
 1439     # . prologue
 1440     55/push-ebp
 1441     89/<- %ebp 4/r32/esp
 1442     # setup
 1443     (clear-stream _test-input-stream)
 1444     (clear-stream $_test-input-buffered-file->buffer)
 1445     (clear-stream _test-output-stream)
 1446     (clear-stream $_test-output-buffered-file->buffer)
 1447     #
 1448     (write _test-input-stream "fn f {\n")
 1449     (write _test-input-stream "  var x: (addr int)\n")
 1450     (write _test-input-stream "  g x\n")
 1451     (write _test-input-stream "}\n")
 1452     (write _test-input-stream "fn g a: (addr int) {\n")
 1453     (write _test-input-stream "}\n")
 1454     # convert
 1455     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1456     (flush _test-output-buffered-file)
 1457 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1463     # check output
 1464     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-inout-with-compound-type/0")
 1465     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-inout-with-compound-type/1")
 1466     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-inout-with-compound-type/2")
 1467     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-inout-with-compound-type/3")
 1468     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-inout-with-compound-type/4")
 1469     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-inout-with-compound-type/5")
 1470     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-inout-with-compound-type/6")
 1471     (check-next-stream-line-equal _test-output-stream "    (g *(ebp+0xfffffffc))"  "F - test-convert-function-call-with-inout-with-compound-type/7")
 1472     (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")
 1473     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-inout-with-compound-type/9")
 1474     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-inout-with-compound-type/10")
 1475     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-inout-with-compound-type/11")
 1476     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-inout-with-compound-type/12")
 1477     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-inout-with-compound-type/13")
 1478     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-inout-with-compound-type/14")
 1479     (check-next-stream-line-equal _test-output-stream "g:"                      "F - test-convert-function-call-with-inout-with-compound-type/15")
 1480     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-inout-with-compound-type/16")
 1481     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-inout-with-compound-type/17")
 1482     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-inout-with-compound-type/18")
 1483     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-inout-with-compound-type/19")
 1484     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-inout-with-compound-type/20")
 1485     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-inout-with-compound-type/21")
 1486     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-inout-with-compound-type/22")
 1487     # . epilogue
 1488     89/<- %esp 5/r32/ebp
 1489     5d/pop-to-ebp
 1490     c3/return
 1491 
 1492 test-convert-function-call-with-inout-with-type-parameter:
 1493     # . prologue
 1494     55/push-ebp
 1495     89/<- %ebp 4/r32/esp
 1496     # setup
 1497     (clear-stream _test-input-stream)
 1498     (clear-stream $_test-input-buffered-file->buffer)
 1499     (clear-stream _test-output-stream)
 1500     (clear-stream $_test-output-buffered-file->buffer)
 1501     (clear-stream _test-error-stream)
 1502     (clear-stream $_test-error-buffered-file->buffer)
 1503     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1504     68/push 0/imm32
 1505     68/push 0/imm32
 1506     89/<- %edx 4/r32/esp
 1507     (tailor-exit-descriptor %edx 0x10)
 1508     #
 1509     (write _test-input-stream "fn f {\n")
 1510     (write _test-input-stream "  var x: (addr int)\n")
 1511     (write _test-input-stream "  g x\n")
 1512     (write _test-input-stream "}\n")
 1513     (write _test-input-stream "fn g a: (addr _) {\n")
 1514     (write _test-input-stream "}\n")
 1515     # convert
 1516     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1517     # registers except esp clobbered at this point
 1518     # restore ed
 1519     89/<- %edx 4/r32/esp
 1520     (flush _test-output-buffered-file)
 1521     (flush _test-error-buffered-file)
 1522 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1528     # no error; types matched
 1529     (check-stream-equal _test-error-stream  ""  "F - test-convert-function-call-with-inout-with-type-parameter: error stream should be empty")
 1530     # don't bother checking the generated code; that's in the test 'test-local-clobbered-by-fn-output' below
 1531     # don't restore from ebp
 1532     81 0/subop/add %esp 8/imm32
 1533     # . epilogue
 1534     5d/pop-to-ebp
 1535     c3/return
 1536 
 1537 test-convert-function-call-with-incorrect-inout-type:
 1538     # . prologue
 1539     55/push-ebp
 1540     89/<- %ebp 4/r32/esp
 1541     # setup
 1542     (clear-stream _test-input-stream)
 1543     (clear-stream $_test-input-buffered-file->buffer)
 1544     (clear-stream _test-output-stream)
 1545     (clear-stream $_test-output-buffered-file->buffer)
 1546     (clear-stream _test-error-stream)
 1547     (clear-stream $_test-error-buffered-file->buffer)
 1548     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1549     68/push 0/imm32
 1550     68/push 0/imm32
 1551     89/<- %edx 4/r32/esp
 1552     (tailor-exit-descriptor %edx 0x10)
 1553     #
 1554     (write _test-input-stream "fn f {\n")
 1555     (write _test-input-stream "  var x: int\n")
 1556     (write _test-input-stream "  g x\n")
 1557     (write _test-input-stream "}\n")
 1558     (write _test-input-stream "fn g a: foo {\n")
 1559     (write _test-input-stream "}\n")
 1560     # convert
 1561     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1562     # registers except esp clobbered at this point
 1563     # restore ed
 1564     89/<- %edx 4/r32/esp
 1565     (flush _test-output-buffered-file)
 1566     (flush _test-error-buffered-file)
 1567 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1573     # check output
 1574     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-inout-type: output should be empty")
 1575     (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")
 1576     # check that stop(1) was called
 1577     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-inout-type: exit status")
 1578     # don't restore from ebp
 1579     81 0/subop/add %esp 8/imm32
 1580     5d/pop-to-ebp
 1581     c3/return
 1582 
 1583 test-convert-function-call-with-inout-with-incorrect-compound-type:
 1584     # . prologue
 1585     55/push-ebp
 1586     89/<- %ebp 4/r32/esp
 1587     # setup
 1588     (clear-stream _test-input-stream)
 1589     (clear-stream $_test-input-buffered-file->buffer)
 1590     (clear-stream _test-output-stream)
 1591     (clear-stream $_test-output-buffered-file->buffer)
 1592     (clear-stream _test-error-stream)
 1593     (clear-stream $_test-error-buffered-file->buffer)
 1594     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1595     68/push 0/imm32
 1596     68/push 0/imm32
 1597     89/<- %edx 4/r32/esp
 1598     (tailor-exit-descriptor %edx 0x10)
 1599     #
 1600     (write _test-input-stream "fn f {\n")
 1601     (write _test-input-stream "  var x: (addr int)\n")
 1602     (write _test-input-stream "  g x\n")
 1603     (write _test-input-stream "}\n")
 1604     (write _test-input-stream "fn g a: (addr bool) {\n")
 1605     (write _test-input-stream "}\n")
 1606     # convert
 1607     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1608     # registers except esp clobbered at this point
 1609     # restore ed
 1610     89/<- %edx 4/r32/esp
 1611     (flush _test-output-buffered-file)
 1612     (flush _test-error-buffered-file)
 1613 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1619     # check output
 1620     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-inout-with-incorrect-compound-type: output should be empty")
 1621     (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")
 1622     # don't restore from ebp
 1623     81 0/subop/add %esp 8/imm32
 1624     # . epilogue
 1625     5d/pop-to-ebp
 1626     c3/return
 1627 
 1628 test-convert-function-call-with-inout-with-multiple-type-parameters:
 1629     # . prologue
 1630     55/push-ebp
 1631     89/<- %ebp 4/r32/esp
 1632     # setup
 1633     (clear-stream _test-input-stream)
 1634     (clear-stream $_test-input-buffered-file->buffer)
 1635     (clear-stream _test-output-stream)
 1636     (clear-stream $_test-output-buffered-file->buffer)
 1637     (clear-stream _test-error-stream)
 1638     (clear-stream $_test-error-buffered-file->buffer)
 1639     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1640     68/push 0/imm32
 1641     68/push 0/imm32
 1642     89/<- %edx 4/r32/esp
 1643     (tailor-exit-descriptor %edx 0x10)
 1644     #
 1645     (write _test-input-stream "fn f {\n")
 1646     (write _test-input-stream "  var x: (addr int)\n")
 1647     (write _test-input-stream "  var y: (addr int)\n")
 1648     (write _test-input-stream "  g x, y\n")
 1649     (write _test-input-stream "}\n")
 1650     (write _test-input-stream "fn g a: (addr _), b: (addr _) {\n")
 1651     (write _test-input-stream "}\n")
 1652     # convert
 1653     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1654     # registers except esp clobbered at this point
 1655     # restore ed
 1656     89/<- %edx 4/r32/esp
 1657     (flush _test-output-buffered-file)
 1658     (flush _test-error-buffered-file)
 1659 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1665     # no errors
 1666     (check-stream-equal _test-error-stream  ""  "F - test-convert-function-call-with-inout-with-multiple-type-parameters: error stream should be empty")
 1667     # don't bother checking the generated code
 1668     # don't restore from ebp
 1669     81 0/subop/add %esp 8/imm32
 1670     # . epilogue
 1671     5d/pop-to-ebp
 1672     c3/return
 1673 
 1674 test-type-parameter-matches-rest-of-type:
 1675     # . prologue
 1676     55/push-ebp
 1677     89/<- %ebp 4/r32/esp
 1678     # setup
 1679     (clear-stream _test-input-stream)
 1680     (clear-stream $_test-input-buffered-file->buffer)
 1681     (clear-stream _test-output-stream)
 1682     (clear-stream $_test-output-buffered-file->buffer)
 1683     (clear-stream _test-error-stream)
 1684     (clear-stream $_test-error-buffered-file->buffer)
 1685     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1686     68/push 0/imm32
 1687     68/push 0/imm32
 1688     89/<- %edx 4/r32/esp
 1689     (tailor-exit-descriptor %edx 0x10)
 1690     #
 1691     (write _test-input-stream "fn f {\n")
 1692     (write _test-input-stream "  var x: (addr array int)\n")
 1693     (write _test-input-stream "  g x\n")
 1694     (write _test-input-stream "}\n")
 1695     (write _test-input-stream "fn g a: (addr _) {\n")
 1696     (write _test-input-stream "}\n")
 1697     # convert
 1698     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1699     # registers except esp clobbered at this point
 1700     # restore ed
 1701     89/<- %edx 4/r32/esp
 1702     (flush _test-output-buffered-file)
 1703     (flush _test-error-buffered-file)
 1704 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1710     # no errors
 1711     (check-stream-equal _test-error-stream  ""  "F - test-type-parameter-matches-rest-of-type: error stream should be empty")
 1712     # don't bother checking the generated code
 1713     # don't restore from ebp
 1714     81 0/subop/add %esp 8/imm32
 1715     # . epilogue
 1716     5d/pop-to-ebp
 1717     c3/return
 1718 
 1719 test-convert-function-call-with-inout-with-incompatible-type-parameters:
 1720     # . prologue
 1721     55/push-ebp
 1722     89/<- %ebp 4/r32/esp
 1723     # setup
 1724     (clear-stream _test-input-stream)
 1725     (clear-stream $_test-input-buffered-file->buffer)
 1726     (clear-stream _test-output-stream)
 1727     (clear-stream $_test-output-buffered-file->buffer)
 1728     (clear-stream _test-error-stream)
 1729     (clear-stream $_test-error-buffered-file->buffer)
 1730     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1731     68/push 0/imm32
 1732     68/push 0/imm32
 1733     89/<- %edx 4/r32/esp
 1734     (tailor-exit-descriptor %edx 0x10)
 1735     #
 1736     (write _test-input-stream "fn f {\n")
 1737     (write _test-input-stream "  var x: (addr int)\n")
 1738     (write _test-input-stream "  var y: (addr boolean)\n")
 1739     (write _test-input-stream "  g x, y\n")
 1740     (write _test-input-stream "}\n")
 1741     (write _test-input-stream "fn g a: (addr _T), b: (addr _T) {\n")
 1742     (write _test-input-stream "}\n")
 1743     # convert
 1744     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1745     # registers except esp clobbered at this point
 1746     # restore ed
 1747     89/<- %edx 4/r32/esp
 1748     (flush _test-output-buffered-file)
 1749     (flush _test-error-buffered-file)
 1750 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1756     # check output
 1757     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-inout-with-incompatible-type-parameters: output should be empty")
 1758     (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")
 1759     # don't restore from ebp
 1760     81 0/subop/add %esp 8/imm32
 1761     # . epilogue
 1762     5d/pop-to-ebp
 1763     c3/return
 1764 
 1765 test-convert-function-call-with-too-few-inouts:
 1766     # . prologue
 1767     55/push-ebp
 1768     89/<- %ebp 4/r32/esp
 1769     # setup
 1770     (clear-stream _test-input-stream)
 1771     (clear-stream $_test-input-buffered-file->buffer)
 1772     (clear-stream _test-output-stream)
 1773     (clear-stream $_test-output-buffered-file->buffer)
 1774     (clear-stream _test-error-stream)
 1775     (clear-stream $_test-error-buffered-file->buffer)
 1776     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1777     68/push 0/imm32
 1778     68/push 0/imm32
 1779     89/<- %edx 4/r32/esp
 1780     (tailor-exit-descriptor %edx 0x10)
 1781     #
 1782     (write _test-input-stream "fn f {\n")
 1783     (write _test-input-stream "  g\n")
 1784     (write _test-input-stream "}\n")
 1785     (write _test-input-stream "fn g a: int {\n")
 1786     (write _test-input-stream "}\n")
 1787     # convert
 1788     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1789     # registers except esp clobbered at this point
 1790     # restore ed
 1791     89/<- %edx 4/r32/esp
 1792     (flush _test-output-buffered-file)
 1793     (flush _test-error-buffered-file)
 1794 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1800     # check output
 1801     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-few-inouts: output should be empty")
 1802     (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")
 1803     # check that stop(1) was called
 1804     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-few-inouts: exit status")
 1805     # don't restore from ebp
 1806     81 0/subop/add %esp 8/imm32
 1807     5d/pop-to-ebp
 1808     c3/return
 1809 
 1810 test-convert-function-call-with-too-many-inouts:
 1811     # . prologue
 1812     55/push-ebp
 1813     89/<- %ebp 4/r32/esp
 1814     # setup
 1815     (clear-stream _test-input-stream)
 1816     (clear-stream $_test-input-buffered-file->buffer)
 1817     (clear-stream _test-output-stream)
 1818     (clear-stream $_test-output-buffered-file->buffer)
 1819     (clear-stream _test-error-stream)
 1820     (clear-stream $_test-error-buffered-file->buffer)
 1821     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1822     68/push 0/imm32
 1823     68/push 0/imm32
 1824     89/<- %edx 4/r32/esp
 1825     (tailor-exit-descriptor %edx 0x10)
 1826     #
 1827     (write _test-input-stream "fn f {\n")
 1828     (write _test-input-stream "  var x: int\n")
 1829     (write _test-input-stream "  g x\n")
 1830     (write _test-input-stream "}\n")
 1831     (write _test-input-stream "fn g {\n")
 1832     (write _test-input-stream "}\n")
 1833     # convert
 1834     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1835     # registers except esp clobbered at this point
 1836     # restore ed
 1837     89/<- %edx 4/r32/esp
 1838     (flush _test-output-buffered-file)
 1839     (flush _test-error-buffered-file)
 1840 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1846     # check output
 1847     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-many-inouts: output should be empty")
 1848     (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")
 1849     # check that stop(1) was called
 1850     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-many-inouts: exit status")
 1851     # don't restore from ebp
 1852     81 0/subop/add %esp 8/imm32
 1853     5d/pop-to-ebp
 1854     c3/return
 1855 
 1856 test-convert-function-call-with-incorrect-output-type:
 1857     # . prologue
 1858     55/push-ebp
 1859     89/<- %ebp 4/r32/esp
 1860     # setup
 1861     (clear-stream _test-input-stream)
 1862     (clear-stream $_test-input-buffered-file->buffer)
 1863     (clear-stream _test-output-stream)
 1864     (clear-stream $_test-output-buffered-file->buffer)
 1865     (clear-stream _test-error-stream)
 1866     (clear-stream $_test-error-buffered-file->buffer)
 1867     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1868     68/push 0/imm32
 1869     68/push 0/imm32
 1870     89/<- %edx 4/r32/esp
 1871     (tailor-exit-descriptor %edx 0x10)
 1872     #
 1873     (write _test-input-stream "fn f {\n")
 1874     (write _test-input-stream "  var x/eax: int <- g\n")
 1875     (write _test-input-stream "}\n")
 1876     (write _test-input-stream "fn g -> a/eax: foo {\n")
 1877     (write _test-input-stream "}\n")
 1878     # convert
 1879     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1880     # registers except esp clobbered at this point
 1881     # restore ed
 1882     89/<- %edx 4/r32/esp
 1883     (flush _test-output-buffered-file)
 1884     (flush _test-error-buffered-file)
 1885 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1891     # check output
 1892     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-output-type: output should be empty")
 1893     (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")
 1894     # check that stop(1) was called
 1895     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-output-type: exit status")
 1896     # don't restore from ebp
 1897     81 0/subop/add %esp 8/imm32
 1898     5d/pop-to-ebp
 1899     c3/return
 1900 
 1901 test-convert-function-call-with-too-few-outputs:
 1902     # . prologue
 1903     55/push-ebp
 1904     89/<- %ebp 4/r32/esp
 1905     # setup
 1906     (clear-stream _test-input-stream)
 1907     (clear-stream $_test-input-buffered-file->buffer)
 1908     (clear-stream _test-output-stream)
 1909     (clear-stream $_test-output-buffered-file->buffer)
 1910     (clear-stream _test-error-stream)
 1911     (clear-stream $_test-error-buffered-file->buffer)
 1912     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1913     68/push 0/imm32
 1914     68/push 0/imm32
 1915     89/<- %edx 4/r32/esp
 1916     (tailor-exit-descriptor %edx 0x10)
 1917     #
 1918     (write _test-input-stream "fn f {\n")
 1919     (write _test-input-stream "  g\n")
 1920     (write _test-input-stream "}\n")
 1921     (write _test-input-stream "fn g -> a/eax: int {\n")
 1922     (write _test-input-stream "}\n")
 1923     # convert
 1924     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1925     # registers except esp clobbered at this point
 1926     # restore ed
 1927     89/<- %edx 4/r32/esp
 1928     (flush _test-output-buffered-file)
 1929     (flush _test-error-buffered-file)
 1930 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1936     # check output
 1937     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-few-outputs: output should be empty")
 1938     (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")
 1939     # check that stop(1) was called
 1940     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-few-outputs: exit status")
 1941     # don't restore from ebp
 1942     81 0/subop/add %esp 8/imm32
 1943     5d/pop-to-ebp
 1944     c3/return
 1945 
 1946 test-convert-function-call-with-too-many-outputs:
 1947     # . prologue
 1948     55/push-ebp
 1949     89/<- %ebp 4/r32/esp
 1950     # setup
 1951     (clear-stream _test-input-stream)
 1952     (clear-stream $_test-input-buffered-file->buffer)
 1953     (clear-stream _test-output-stream)
 1954     (clear-stream $_test-output-buffered-file->buffer)
 1955     (clear-stream _test-error-stream)
 1956     (clear-stream $_test-error-buffered-file->buffer)
 1957     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1958     68/push 0/imm32
 1959     68/push 0/imm32
 1960     89/<- %edx 4/r32/esp
 1961     (tailor-exit-descriptor %edx 0x10)
 1962     #
 1963     (write _test-input-stream "fn f {\n")
 1964     (write _test-input-stream "  var x/eax: int <- g\n")
 1965     (write _test-input-stream "}\n")
 1966     (write _test-input-stream "fn g {\n")
 1967     (write _test-input-stream "}\n")
 1968     # convert
 1969     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1970     # registers except esp clobbered at this point
 1971     # restore ed
 1972     89/<- %edx 4/r32/esp
 1973     (flush _test-output-buffered-file)
 1974     (flush _test-error-buffered-file)
 1975 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1981     # check output
 1982     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-many-outputs: output should be empty")
 1983     (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")
 1984     # check that stop(1) was called
 1985     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-many-outputs: exit status")
 1986     # don't restore from ebp
 1987     81 0/subop/add %esp 8/imm32
 1988     5d/pop-to-ebp
 1989     c3/return
 1990 
 1991 test-convert-function-call-with-incorrect-output-register:
 1992     # . prologue
 1993     55/push-ebp
 1994     89/<- %ebp 4/r32/esp
 1995     # setup
 1996     (clear-stream _test-input-stream)
 1997     (clear-stream $_test-input-buffered-file->buffer)
 1998     (clear-stream _test-output-stream)
 1999     (clear-stream $_test-output-buffered-file->buffer)
 2000     (clear-stream _test-error-stream)
 2001     (clear-stream $_test-error-buffered-file->buffer)
 2002     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 2003     68/push 0/imm32
 2004     68/push 0/imm32
 2005     89/<- %edx 4/r32/esp
 2006     (tailor-exit-descriptor %edx 0x10)
 2007     #
 2008     (write _test-input-stream "fn f {\n")
 2009     (write _test-input-stream "  var x/ecx: int <- g\n")
 2010     (write _test-input-stream "}\n")
 2011     (write _test-input-stream "fn g -> a/eax: int {\n")
 2012     (write _test-input-stream "}\n")
 2013     # convert
 2014     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 2015     # registers except esp clobbered at this point
 2016     # restore ed
 2017     89/<- %edx 4/r32/esp
 2018     (flush _test-output-buffered-file)
 2019     (flush _test-error-buffered-file)
 2020 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 2026     # check output
 2027     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-output-register: output should be empty")
 2028     (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")
 2029     # check that stop(1) was called
 2030     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-output-register: exit status")
 2031     # don't restore from ebp
 2032     81 0/subop/add %esp 8/imm32
 2033     5d/pop-to-ebp
 2034     c3/return
 2035 
 2036 test-convert-function-with-local-var-dereferenced:
 2037     # . prologue
 2038     55/push-ebp
 2039     89/<- %ebp 4/r32/esp
 2040     # setup
 2041     (clear-stream _test-input-stream)
 2042     (clear-stream $_test-input-buffered-file->buffer)
 2043     (clear-stream _test-output-stream)
 2044     (clear-stream $_test-output-buffered-file->buffer)
 2045     #
 2046     (write _test-input-stream "fn foo {\n")
 2047     (write _test-input-stream "  var x/ecx: (addr int) <- copy 0\n")
 2048     (write _test-input-stream "  increment *x\n")
 2049     (write _test-input-stream "}\n")
 2050     # convert
 2051     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2052     (flush _test-output-buffered-file)
 2053 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2059     # check output
 2060     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-dereferenced/0")
 2061     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-dereferenced/1")
 2062     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-dereferenced/2")
 2063     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-dereferenced/3")
 2064     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-dereferenced/4")
 2065     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-dereferenced/5")
 2066     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-dereferenced/6")
 2067     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-local-var-dereferenced/7")
 2068     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *ecx"  "F - test-convert-function-with-local-var-dereferenced/8")
 2069     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-dereferenced/9")
 2070     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-dereferenced/10")
 2071     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-dereferenced/11")
 2072     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-dereferenced/12")
 2073     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-dereferenced/13")
 2074     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-dereferenced/14")
 2075     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-dereferenced/15")
 2076     # . epilogue
 2077     89/<- %esp 5/r32/ebp
 2078     5d/pop-to-ebp
 2079     c3/return
 2080 
 2081 # variables of type 'byte' are not allowed on the stack
 2082 test-convert-function-with-byte-operations:
 2083     # . prologue
 2084     55/push-ebp
 2085     89/<- %ebp 4/r32/esp
 2086     # setup
 2087     (clear-stream _test-input-stream)
 2088     (clear-stream $_test-input-buffered-file->buffer)
 2089     (clear-stream _test-output-stream)
 2090     (clear-stream $_test-output-buffered-file->buffer)
 2091     #
 2092     (write _test-input-stream "fn foo {\n")
 2093     (write _test-input-stream "  var x/eax: byte <- copy 0\n")
 2094     (write _test-input-stream "  var y/ecx: byte <- copy 0\n")
 2095     (write _test-input-stream "  y <- copy-byte x\n")
 2096     (write _test-input-stream "  var z/edx: (addr byte) <- copy 0\n")
 2097     (write _test-input-stream "  y <- copy-byte *z\n")
 2098     (write _test-input-stream "  copy-byte-to *z, x\n")
 2099     (write _test-input-stream "}\n")
 2100     # convert
 2101     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2102     (flush _test-output-buffered-file)
 2103 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2109     # check output
 2110     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-function-with-byte-operations/0")
 2111     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-function-with-byte-operations/1")
 2112     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-function-with-byte-operations/2")
 2113     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-function-with-byte-operations/3")
 2114     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-function-with-byte-operations/4")
 2115     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-function-with-byte-operations/5")
 2116     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-function-with-byte-operations/6")
 2117     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-function-with-byte-operations/7")
 2118     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-function-with-byte-operations/8")
 2119     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"                  "F - test-convert-function-with-byte-operations/9")
 2120     (check-next-stream-line-equal _test-output-stream "    8a/byte-> %eax 0x00000001/r32"           "F - test-convert-function-with-byte-operations/10")
 2121     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %edx"                    "F - test-convert-function-with-byte-operations/11")
 2122     (check-next-stream-line-equal _test-output-stream "    ba/copy-to-edx 0/imm32"                  "F - test-convert-function-with-byte-operations/12")
 2123     (check-next-stream-line-equal _test-output-stream "    8a/byte-> *edx 0x00000001/r32"           "F - test-convert-function-with-byte-operations/13")
 2124     (check-next-stream-line-equal _test-output-stream "    88/byte<- *edx 0x00000000/r32"           "F - test-convert-function-with-byte-operations/14")
 2125     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %edx"                     "F - test-convert-function-with-byte-operations/15")
 2126     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-function-with-byte-operations/16")
 2127     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-function-with-byte-operations/17")
 2128     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-function-with-byte-operations/18")
 2129     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-function-with-byte-operations/19")
 2130     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-function-with-byte-operations/20")
 2131     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-function-with-byte-operations/21")
 2132     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-function-with-byte-operations/22")
 2133     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-function-with-byte-operations/23")
 2134     # . epilogue
 2135     89/<- %esp 5/r32/ebp
 2136     5d/pop-to-ebp
 2137     c3/return
 2138 
 2139 # variables of type 'byte' _can_ be function args. They then occupy 4 bytes.
 2140 test-copy-byte-var-from-fn-arg:
 2141     # . prologue
 2142     55/push-ebp
 2143     89/<- %ebp 4/r32/esp
 2144     # setup
 2145     (clear-stream _test-input-stream)
 2146     (clear-stream $_test-input-buffered-file->buffer)
 2147     (clear-stream _test-output-stream)
 2148     (clear-stream $_test-output-buffered-file->buffer)
 2149     #
 2150     (write _test-input-stream "fn foo x: byte, y: int {\n")
 2151     (write _test-input-stream "  var a/eax: byte <- copy x\n")
 2152     (write _test-input-stream "  var b/eax: int <- copy y\n")
 2153     (write _test-input-stream "}\n")
 2154     # convert
 2155     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2156     (flush _test-output-buffered-file)
 2157 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2163     # check output
 2164     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-copy-byte-from-fn-arg/0")
 2165     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-copy-byte-from-fn-arg/1")
 2166     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-copy-byte-from-fn-arg/2")
 2167     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-copy-byte-from-fn-arg/3")
 2168     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-copy-byte-from-fn-arg/4")
 2169     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-copy-byte-from-fn-arg/5")
 2170     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-copy-byte-from-fn-arg/6")
 2171     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-copy-byte-from-fn-arg/7")
 2172     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x0000000c) 0x00000000/r32"  "F - test-copy-byte-from-fn-arg/8")
 2173     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"   "F - test-copy-byte-from-fn-arg/9")
 2174     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-copy-byte-from-fn-arg/10")
 2175     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-copy-byte-from-fn-arg/11")
 2176     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-copy-byte-from-fn-arg/12")
 2177     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-copy-byte-from-fn-arg/13")
 2178     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-copy-byte-from-fn-arg/14")
 2179     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-copy-byte-from-fn-arg/15")
 2180     # . epilogue
 2181     89/<- %esp 5/r32/ebp
 2182     5d/pop-to-ebp
 2183     c3/return
 2184 
 2185 test-convert-compare-register-with-literal:
 2186     # . prologue
 2187     55/push-ebp
 2188     89/<- %ebp 4/r32/esp
 2189     # setup
 2190     (clear-stream _test-input-stream)
 2191     (clear-stream $_test-input-buffered-file->buffer)
 2192     (clear-stream _test-output-stream)
 2193     (clear-stream $_test-output-buffered-file->buffer)
 2194     #
 2195     (write _test-input-stream "fn foo {\n")
 2196     (write _test-input-stream "  var x/ecx: int <- copy 0\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 Stderr 0)
 2201     (flush _test-output-buffered-file)
 2202 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2208     # check output
 2209     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-compare-register-with-literal/0")
 2210     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-compare-register-with-literal/1")
 2211     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-compare-register-with-literal/2")
 2212     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-compare-register-with-literal/3")
 2213     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-compare-register-with-literal/4")
 2214     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-compare-register-with-literal/5")
 2215     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
 2216     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-compare-register-with-literal/7")
 2217     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %ecx 0/imm32"  "F - test-convert-compare-register-with-literal/8")
 2218     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
 2219     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-compare-register-with-literal/10")
 2220     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-compare-register-with-literal/11")
 2221     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-compare-register-with-literal/12")
 2222     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-compare-register-with-literal/13")
 2223     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-compare-register-with-literal/14")
 2224     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-compare-register-with-literal/15")
 2225     # . epilogue
 2226     89/<- %esp 5/r32/ebp
 2227     5d/pop-to-ebp
 2228     c3/return
 2229 
 2230 test-unknown-variable:
 2231     # . prologue
 2232     55/push-ebp
 2233     89/<- %ebp 4/r32/esp
 2234     # setup
 2235     (clear-stream _test-input-stream)
 2236     (clear-stream $_test-input-buffered-file->buffer)
 2237     (clear-stream _test-output-stream)
 2238     (clear-stream $_test-output-buffered-file->buffer)
 2239     (clear-stream _test-error-stream)
 2240     (clear-stream $_test-error-buffered-file->buffer)
 2241     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 2242     68/push 0/imm32
 2243     68/push 0/imm32
 2244     89/<- %edx 4/r32/esp
 2245     (tailor-exit-descriptor %edx 0x10)
 2246     #
 2247     (write _test-input-stream "fn foo {\n")
 2248     (write _test-input-stream "  compare x, 0\n")
 2249     (write _test-input-stream "}\n")
 2250     # convert
 2251     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 2252     # registers except esp clobbered at this point
 2253     # restore ed
 2254     89/<- %edx 4/r32/esp
 2255     (flush _test-output-buffered-file)
 2256     (flush _test-error-buffered-file)
 2257 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 2263     # check output
 2264     (check-stream-equal _test-output-stream  ""  "F - test-unknown-variable: output should be empty")
 2265     (check-next-stream-line-equal _test-error-stream  "fn foo: unknown variable 'x'"  "F - test-unknown-variable: error message")
 2266     # check that stop(1) was called
 2267     (check-ints-equal *(edx+4) 2 "F - test-unknown-variable: exit status")
 2268     # don't restore from ebp
 2269     81 0/subop/add %esp 8/imm32
 2270     # . epilogue
 2271     5d/pop-to-ebp
 2272     c3/return
 2273 
 2274 test-convert-function-with-local-var-in-block:
 2275     # . prologue
 2276     55/push-ebp
 2277     89/<- %ebp 4/r32/esp
 2278     # setup
 2279     (clear-stream _test-input-stream)
 2280     (clear-stream $_test-input-buffered-file->buffer)
 2281     (clear-stream _test-output-stream)
 2282     (clear-stream $_test-output-buffered-file->buffer)
 2283     #
 2284     (write _test-input-stream "fn foo {\n")
 2285     (write _test-input-stream "  {\n")
 2286     (write _test-input-stream "    var x: int\n")
 2287     (write _test-input-stream "    increment x\n")
 2288     (write _test-input-stream "  }\n")
 2289     (write _test-input-stream "}\n")
 2290     # convert
 2291     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2292     (flush _test-output-buffered-file)
 2293 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2299     # check output
 2300     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-block/0")
 2301     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-block/1")
 2302     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-block/2")
 2303     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-block/3")
 2304     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-block/4")
 2305     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-block/5")
 2306     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-block/6")
 2307     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-local-var-in-block/7")
 2308     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-block/8")
 2309     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-block/9")
 2310     (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")
 2311     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-block/11")
 2312     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-local-var-in-block/12")
 2313     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-block/13")
 2314     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-block/14")
 2315     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-block/15")
 2316     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-block/16")
 2317     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-block/17")
 2318     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-block/18")
 2319     # . epilogue
 2320     89/<- %esp 5/r32/ebp
 2321     5d/pop-to-ebp
 2322     c3/return
 2323 
 2324 test-convert-function-with-local-var-in-named-block:
 2325     # . prologue
 2326     55/push-ebp
 2327     89/<- %ebp 4/r32/esp
 2328     # setup
 2329     (clear-stream _test-input-stream)
 2330     (clear-stream $_test-input-buffered-file->buffer)
 2331     (clear-stream _test-output-stream)
 2332     (clear-stream $_test-output-buffered-file->buffer)
 2333     #
 2334     (write _test-input-stream "fn foo {\n")
 2335     (write _test-input-stream "  $bar: {\n")
 2336     (write _test-input-stream "    var x: int\n")
 2337     (write _test-input-stream "    increment x\n")
 2338     (write _test-input-stream "  }\n")
 2339     (write _test-input-stream "}\n")
 2340     # convert
 2341     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2342     (flush _test-output-buffered-file)
 2343 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2349     # check output
 2350     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-named-block/0")
 2351     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-named-block/1")
 2352     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-named-block/2")
 2353     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-named-block/3")
 2354     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-named-block/4")
 2355     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-named-block/5")
 2356     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-named-block/6")
 2357     (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-local-var-in-named-block/7")
 2358     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-named-block/8")
 2359     (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")
 2360     (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")
 2361     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-named-block/11")
 2362     (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-local-var-in-named-block/12")
 2363     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-named-block/13")
 2364     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-named-block/14")
 2365     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-named-block/15")
 2366     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-named-block/16")
 2367     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-named-block/17")
 2368     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-named-block/18")
 2369     # . epilogue
 2370     89/<- %esp 5/r32/ebp
 2371     5d/pop-to-ebp
 2372     c3/return
 2373 
 2374 test-unknown-variable-in-named-block:
 2375     # . prologue
 2376     55/push-ebp
 2377     89/<- %ebp 4/r32/esp
 2378     # setup
 2379     (clear-stream _test-input-stream)
 2380     (clear-stream $_test-input-buffered-file->buffer)
 2381     (clear-stream _test-output-stream)
 2382     (clear-stream $_test-output-buffered-file->buffer)
 2383     (clear-stream _test-error-stream)
 2384     (clear-stream $_test-error-buffered-file->buffer)
 2385     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 2386     68/push 0/imm32
 2387     68/push 0/imm32
 2388     89/<- %edx 4/r32/esp
 2389     (tailor-exit-descriptor %edx 0x10)
 2390     #
 2391     (write _test-input-stream "fn foo {\n")
 2392     (write _test-input-stream "  $a: {\n")
 2393     (write _test-input-stream "    compare x, 0\n")
 2394     (write _test-input-stream "  }\n")
 2395     (write _test-input-stream "}\n")
 2396     # convert
 2397     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 2398     # registers except esp clobbered at this point
 2399     # restore ed
 2400     89/<- %edx 4/r32/esp
 2401     (flush _test-output-buffered-file)
 2402     (flush _test-error-buffered-file)
 2403 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 2409     # check output
 2410     (check-stream-equal _test-output-stream  ""  "F - test-unknown-variable-in-named-block: output should be empty")
 2411     (check-next-stream-line-equal _test-error-stream  "fn foo: unknown variable 'x'"  "F - test-unknown-variable-in-named-block: error message")
 2412     # check that stop(1) was called
 2413     (check-ints-equal *(edx+4) 2 "F - test-unknown-variable-in-named-block: exit status")
 2414     # don't restore from ebp
 2415     81 0/subop/add %esp 8/imm32
 2416     # . epilogue
 2417     5d/pop-to-ebp
 2418     c3/return
 2419 
 2420 test-always-shadow-outermost-reg-vars-in-function:
 2421     # . prologue
 2422     55/push-ebp
 2423     89/<- %ebp 4/r32/esp
 2424     # setup
 2425     (clear-stream _test-input-stream)
 2426     (clear-stream $_test-input-buffered-file->buffer)
 2427     (clear-stream _test-output-stream)
 2428     (clear-stream $_test-output-buffered-file->buffer)
 2429     #
 2430     (write _test-input-stream "fn foo {\n")
 2431     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2432     (write _test-input-stream "}\n")
 2433     # convert
 2434     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2435     (flush _test-output-buffered-file)
 2436 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2442     # check output
 2443     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-always-shadow-outermost-reg-vars-in-function/0")
 2444     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-always-shadow-outermost-reg-vars-in-function/1")
 2445     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-always-shadow-outermost-reg-vars-in-function/2")
 2446     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-always-shadow-outermost-reg-vars-in-function/3")
 2447     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-always-shadow-outermost-reg-vars-in-function/4")
 2448     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-always-shadow-outermost-reg-vars-in-function/5")
 2449     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
 2450     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-always-shadow-outermost-reg-vars-in-function/8")
 2451     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
 2452     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-always-shadow-outermost-reg-vars-in-function/12")
 2453     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-always-shadow-outermost-reg-vars-in-function/13")
 2454     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-always-shadow-outermost-reg-vars-in-function/14")
 2455     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-always-shadow-outermost-reg-vars-in-function/15")
 2456     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-always-shadow-outermost-reg-vars-in-function/16")
 2457     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-always-shadow-outermost-reg-vars-in-function/17")
 2458     # . epilogue
 2459     89/<- %esp 5/r32/ebp
 2460     5d/pop-to-ebp
 2461     c3/return
 2462 
 2463 _pending-test-clobber-dead-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 "}\n")
 2479     # convert
 2480     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2481     (flush _test-output-buffered-file)
 2482 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2488     # check output
 2489     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-clobber-dead-local/0")
 2490     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-clobber-dead-local/1")
 2491     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-clobber-dead-local/2")
 2492     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-clobber-dead-local/3")
 2493     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-clobber-dead-local/4")
 2494     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-clobber-dead-local/5")
 2495     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-clobber-dead-local/6")
 2496     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-clobber-dead-local/7")
 2497     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-clobber-dead-local/8")
 2498     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-clobber-dead-local/9")
 2499     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-clobber-dead-local/10")  # no push/pop here
 2500     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-clobber-dead-local/11")
 2501     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-clobber-dead-local/12")
 2502     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-clobber-dead-local/13")
 2503     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-clobber-dead-local/14")
 2504     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-clobber-dead-local/15")
 2505     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-clobber-dead-local/16")
 2506     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-clobber-dead-local/17")
 2507     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-clobber-dead-local/18")
 2508     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-clobber-dead-local/19")
 2509     # . epilogue
 2510     89/<- %esp 5/r32/ebp
 2511     5d/pop-to-ebp
 2512     c3/return
 2513 
 2514 test-shadow-live-local:
 2515     # . prologue
 2516     55/push-ebp
 2517     89/<- %ebp 4/r32/esp
 2518     # setup
 2519     (clear-stream _test-input-stream)
 2520     (clear-stream $_test-input-buffered-file->buffer)
 2521     (clear-stream _test-output-stream)
 2522     (clear-stream $_test-output-buffered-file->buffer)
 2523     #
 2524     (write _test-input-stream "fn foo {\n")
 2525     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2526     (write _test-input-stream "  {\n")
 2527     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 2528     (write _test-input-stream "  }\n")
 2529     (write _test-input-stream "  x <- increment\n")
 2530     (write _test-input-stream "}\n")
 2531     # convert
 2532     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2533     (flush _test-output-buffered-file)
 2534 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2540     # check output
 2541     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-live-local/0")
 2542     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-live-local/1")
 2543     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-live-local/2")
 2544     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-live-local/3")
 2545     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-live-local/4")
 2546     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-live-local/5")
 2547     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-live-local/6")
 2548     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-live-local/7")
 2549     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-live-local/8")
 2550     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-live-local/9")
 2551     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-live-local/10")
 2552     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-live-local/11")
 2553     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-live-local/12")
 2554     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-live-local/13")
 2555     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-live-local/14")
 2556     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-live-local/15")
 2557     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-live-local/16")
 2558     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-live-local/17")
 2559     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-live-local/18")
 2560     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-live-local/19")
 2561     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-live-local/20")
 2562     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-live-local/21")
 2563     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-live-local/22")
 2564     # . epilogue
 2565     89/<- %esp 5/r32/ebp
 2566     5d/pop-to-ebp
 2567     c3/return
 2568 
 2569 test-shadow-name:
 2570     # . prologue
 2571     55/push-ebp
 2572     89/<- %ebp 4/r32/esp
 2573     # setup
 2574     (clear-stream _test-input-stream)
 2575     (clear-stream $_test-input-buffered-file->buffer)
 2576     (clear-stream _test-output-stream)
 2577     (clear-stream $_test-output-buffered-file->buffer)
 2578     #
 2579     (write _test-input-stream "fn foo {\n")
 2580     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2581     (write _test-input-stream "  {\n")
 2582     (write _test-input-stream "    var x/edx: int <- copy 4\n")
 2583     (write _test-input-stream "  }\n")
 2584     (write _test-input-stream "  x <- increment\n")
 2585     (write _test-input-stream "}\n")
 2586     # convert
 2587     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2588     (flush _test-output-buffered-file)
 2589 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2595     # check output
 2596     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-name/0")
 2597     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-name/1")
 2598     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-name/2")
 2599     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-name/3")
 2600     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-name/4")
 2601     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-name/5")
 2602     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-name/6")
 2603     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-name/7")
 2604     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-name/8")
 2605     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-name/9")
 2606     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %edx"  "F - test-shadow-name/10")
 2607     (check-next-stream-line-equal _test-output-stream "      ba/copy-to-edx 4/imm32"  "F - test-shadow-name/11")
 2608     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %edx" "F - test-shadow-name/12")
 2609     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-name/13")
 2610     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-name/14")
 2611     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-name/15")
 2612     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-name/16")
 2613     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-name/17")
 2614     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-name/18")
 2615     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-name/19")
 2616     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-name/20")
 2617     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-name/21")
 2618     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-name/22")
 2619     # . epilogue
 2620     89/<- %esp 5/r32/ebp
 2621     5d/pop-to-ebp
 2622     c3/return
 2623 
 2624 test-shadow-name-2:
 2625     # . prologue
 2626     55/push-ebp
 2627     89/<- %ebp 4/r32/esp
 2628     # setup
 2629     (clear-stream _test-input-stream)
 2630     (clear-stream $_test-input-buffered-file->buffer)
 2631     (clear-stream _test-output-stream)
 2632     (clear-stream $_test-output-buffered-file->buffer)
 2633     #
 2634     (write _test-input-stream "fn foo {\n")
 2635     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2636     (write _test-input-stream "  {\n")
 2637     (write _test-input-stream "    var x/edx: int <- copy 4\n")
 2638     (write _test-input-stream "    var y/ecx: int <- copy 5\n")
 2639     (write _test-input-stream "  }\n")
 2640     (write _test-input-stream "  x <- increment\n")
 2641     (write _test-input-stream "}\n")
 2642     # convert
 2643     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2644     (flush _test-output-buffered-file)
 2645 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2651     # check output
 2652     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-name-2/0")
 2653     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-name-2/1")
 2654     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-name-2/2")
 2655     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-name-2/3")
 2656     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-name-2/4")
 2657     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-name-2/5")
 2658     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-name-2/6")
 2659     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-name-2/7")
 2660     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-name-2/8")
 2661     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-name-2/9")
 2662     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %edx"  "F - test-shadow-name-2/10")
 2663     (check-next-stream-line-equal _test-output-stream "      ba/copy-to-edx 4/imm32"  "F - test-shadow-name-2/11")
 2664     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-name-2/12")
 2665     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 5/imm32"  "F - test-shadow-name-2/13")
 2666     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-name-2/14")
 2667     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %edx" "F - test-shadow-name-2/15")
 2668     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-name-2/16")
 2669     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-name-2/17")
 2670     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-name-2/18")
 2671     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-name-2/19")
 2672     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-name-2/20")
 2673     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-name-2/21")
 2674     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-name-2/22")
 2675     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-name-2/23")
 2676     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-name-2/24")
 2677     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-name-2/25")
 2678     # . epilogue
 2679     89/<- %esp 5/r32/ebp
 2680     5d/pop-to-ebp
 2681     c3/return
 2682 
 2683 test-do-not-spill-same-register-in-block:
 2684     # . prologue
 2685     55/push-ebp
 2686     89/<- %ebp 4/r32/esp
 2687     # setup
 2688     (clear-stream _test-input-stream)
 2689     (clear-stream $_test-input-buffered-file->buffer)
 2690     (clear-stream _test-output-stream)
 2691     (clear-stream $_test-output-buffered-file->buffer)
 2692     #
 2693     (write _test-input-stream "fn foo {\n")
 2694     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2695     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2696     (write _test-input-stream "  y <- increment\n")
 2697     (write _test-input-stream "}\n")
 2698     # convert
 2699     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2700     (flush _test-output-buffered-file)
 2701 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2707     # check output
 2708     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-do-not-spill-same-register-in-block/0")
 2709     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-do-not-spill-same-register-in-block/1")
 2710     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-do-not-spill-same-register-in-block/2")
 2711     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-do-not-spill-same-register-in-block/3")
 2712     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-do-not-spill-same-register-in-block/4")
 2713     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-do-not-spill-same-register-in-block/5")
 2714     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-do-not-spill-same-register-in-block/6")
 2715     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-do-not-spill-same-register-in-block/7")
 2716     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-do-not-spill-same-register-in-block/8")
 2717     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-do-not-spill-same-register-in-block/9")
 2718     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-do-not-spill-same-register-in-block/10")
 2719     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-do-not-spill-same-register-in-block/11")
 2720     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-do-not-spill-same-register-in-block/12")
 2721     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-do-not-spill-same-register-in-block/13")
 2722     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-do-not-spill-same-register-in-block/14")
 2723     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-do-not-spill-same-register-in-block/15")
 2724     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-do-not-spill-same-register-in-block/16")
 2725     # . epilogue
 2726     89/<- %esp 5/r32/ebp
 2727     5d/pop-to-ebp
 2728     c3/return
 2729 
 2730 test-spill-different-register-in-block:
 2731     # . prologue
 2732     55/push-ebp
 2733     89/<- %ebp 4/r32/esp
 2734     # setup
 2735     (clear-stream _test-input-stream)
 2736     (clear-stream $_test-input-buffered-file->buffer)
 2737     (clear-stream _test-output-stream)
 2738     (clear-stream $_test-output-buffered-file->buffer)
 2739     #
 2740     (write _test-input-stream "fn foo {\n")
 2741     (write _test-input-stream "  var x/eax: int <- copy 3\n")
 2742     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2743     (write _test-input-stream "  y <- 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-spill-different-register-in-block/0")
 2756     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-spill-different-register-in-block/1")
 2757     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-spill-different-register-in-block/2")
 2758     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-spill-different-register-in-block/3")
 2759     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-spill-different-register-in-block/4")
 2760     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-spill-different-register-in-block/5")
 2761     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-spill-different-register-in-block/6")
 2762     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-spill-different-register-in-block/7")
 2763     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-spill-different-register-in-block/8")
 2764     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-spill-different-register-in-block/9")
 2765     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-spill-different-register-in-block/10")
 2766     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-spill-different-register-in-block/11")
 2767     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-spill-different-register-in-block/12")
 2768     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-spill-different-register-in-block/13")
 2769     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-spill-different-register-in-block/14")
 2770     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-spill-different-register-in-block/15")
 2771     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-spill-different-register-in-block/16")
 2772     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-spill-different-register-in-block/17")
 2773     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-spill-different-register-in-block/18")
 2774     # . epilogue
 2775     89/<- %esp 5/r32/ebp
 2776     5d/pop-to-ebp
 2777     c3/return
 2778 
 2779 test-shadow-live-output:
 2780     # . prologue
 2781     55/push-ebp
 2782     89/<- %ebp 4/r32/esp
 2783     # setup
 2784     (clear-stream _test-input-stream)
 2785     (clear-stream $_test-input-buffered-file->buffer)
 2786     (clear-stream _test-output-stream)
 2787     (clear-stream $_test-output-buffered-file->buffer)
 2788     #
 2789     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2790     (write _test-input-stream "  x <- copy 3\n")
 2791     (write _test-input-stream "  {\n")
 2792     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 2793     (write _test-input-stream "  }\n")
 2794     (write _test-input-stream "  x <- increment\n")
 2795     (write _test-input-stream "}\n")
 2796     # convert
 2797     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2798     (flush _test-output-buffered-file)
 2799 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2805     # check output
 2806     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-live-output/0")
 2807     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-live-output/1")
 2808     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-live-output/2")
 2809     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-live-output/3")
 2810     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-live-output/4")
 2811     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-live-output/5")
 2812     (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
 2813     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-live-output/8")
 2814     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-live-output/9")
 2815     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-live-output/10")
 2816     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-live-output/11")
 2817     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-live-output/12")
 2818     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-live-output/13")
 2819     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-live-output/14")
 2820     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-live-output/15")
 2821     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-live-output/17")
 2822     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-live-output/18")
 2823     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-live-output/19")
 2824     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-live-output/20")
 2825     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-live-output/21")
 2826     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-live-output/21")
 2827     # . epilogue
 2828     89/<- %esp 5/r32/ebp
 2829     5d/pop-to-ebp
 2830     c3/return
 2831 
 2832 test-stmt-defines-output-in-same-register-as-inout:
 2833     # . prologue
 2834     55/push-ebp
 2835     89/<- %ebp 4/r32/esp
 2836     # setup
 2837     (clear-stream _test-input-stream)
 2838     (clear-stream $_test-input-buffered-file->buffer)
 2839     (clear-stream _test-output-stream)
 2840     (clear-stream $_test-output-buffered-file->buffer)
 2841     (clear-stream _test-error-stream)
 2842     (clear-stream $_test-error-buffered-file->buffer)
 2843     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 2844     68/push 0/imm32
 2845     68/push 0/imm32
 2846     89/<- %edx 4/r32/esp
 2847     (tailor-exit-descriptor %edx 0x10)
 2848     #
 2849     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2850     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2851     (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
 2852     (write _test-input-stream "}\n")
 2853     # convert
 2854     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 2855     # registers except esp clobbered at this point
 2856     # restore ed
 2857     89/<- %edx 4/r32/esp
 2858     (flush _test-output-buffered-file)
 2859     (flush _test-error-buffered-file)
 2860 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 2866     # no error; we looked up 'y' correctly before pushing the binding for 'x'
 2867     (check-stream-equal _test-error-stream  ""  "F - test-stmt-defines-output-in-same-register-as-inout: error stream should be empty")
 2868     # don't bother checking the generated code; that's in the test 'test-local-clobbered-by-fn-output' below
 2869     # don't restore from ebp
 2870     81 0/subop/add %esp 8/imm32
 2871     # . epilogue
 2872     5d/pop-to-ebp
 2873     c3/return
 2874 
 2875 test-local-clobbered-by-fn-output:
 2876     # . prologue
 2877     55/push-ebp
 2878     89/<- %ebp 4/r32/esp
 2879     # setup
 2880     (clear-stream _test-input-stream)
 2881     (clear-stream $_test-input-buffered-file->buffer)
 2882     (clear-stream _test-output-stream)
 2883     (clear-stream $_test-output-buffered-file->buffer)
 2884     #
 2885     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2886     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2887     (write _test-input-stream "  x <- copy y\n")
 2888     (write _test-input-stream "}\n")
 2889     # convert
 2890     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2891     (flush _test-output-buffered-file)
 2892 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2898     # check output
 2899     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-local-clobbered-by-fn-output/0")
 2900     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-local-clobbered-by-fn-output/1")
 2901     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-local-clobbered-by-fn-output/2")
 2902     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-local-clobbered-by-fn-output/3")
 2903     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-local-clobbered-by-fn-output/4")
 2904     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-local-clobbered-by-fn-output/5")
 2905     (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
 2906     (check-next-stream-line-equal _test-output-stream "    89/<- %ecx 0x00000001/r32"  "F - test-local-clobbered-by-fn-output/7")
 2907     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-local-clobbered-by-fn-output/8")
 2908     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-local-clobbered-by-fn-output/9")
 2909     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-local-clobbered-by-fn-output/10")
 2910     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-local-clobbered-by-fn-output/11")
 2911     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-local-clobbered-by-fn-output/12")
 2912     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-local-clobbered-by-fn-output/13")
 2913     # . epilogue
 2914     89/<- %esp 5/r32/ebp
 2915     5d/pop-to-ebp
 2916     c3/return
 2917 
 2918 test-read-output:
 2919     # . prologue
 2920     55/push-ebp
 2921     89/<- %ebp 4/r32/esp
 2922     # setup
 2923     (clear-stream _test-input-stream)
 2924     (clear-stream $_test-input-buffered-file->buffer)
 2925     (clear-stream _test-output-stream)
 2926     (clear-stream $_test-output-buffered-file->buffer)
 2927     #
 2928     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2929     (write _test-input-stream "  x <- copy 0x34\n")
 2930     (write _test-input-stream "  compare x, 0x35\n")
 2931     (write _test-input-stream "}\n")
 2932     # convert
 2933     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2934     (flush _test-output-buffered-file)
 2935 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2941     # check output
 2942     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-read-output/0")
 2943     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-read-output/1")
 2944     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-read-output/2")
 2945     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-read-output/3")
 2946     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-read-output/4")
 2947     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-read-output/5")
 2948     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0x34/imm32"  "F - test-read-output/6")
 2949     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %ecx 0x35/imm32"  "F - test-read-output/7")
 2950     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-read-output/8")
 2951     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-read-output/9")
 2952     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-read-output/10")
 2953     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-read-output/11")
 2954     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-read-output/12")
 2955     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-read-output/13")
 2956     # . epilogue
 2957     89/<- %esp 5/r32/ebp
 2958     5d/pop-to-ebp
 2959     c3/return
 2960 
 2961 test-fn-output-written-in-inner-block:
 2962     # . prologue
 2963     55/push-ebp
 2964     89/<- %ebp 4/r32/esp
 2965     # setup
 2966     (clear-stream _test-input-stream)
 2967     (clear-stream $_test-input-buffered-file->buffer)
 2968     (clear-stream _test-output-stream)
 2969     (clear-stream $_test-output-buffered-file->buffer)
 2970     #
 2971     (write _test-input-stream "fn foo -> out/edi: int {\n")
 2972     (write _test-input-stream "  var a/eax: int <- copy 3\n")  # define outer local
 2973     (write _test-input-stream "  {\n")
 2974     (write _test-input-stream "    var a/ecx: int <- copy 4\n")  # shadow outer local
 2975     (write _test-input-stream "    out <- copy a\n")  # write to fn output
 2976     (write _test-input-stream "  }\n")
 2977     (write _test-input-stream "  compare a, 0\n")  # use outer local
 2978     (write _test-input-stream "}\n")
 2979     # convert
 2980     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2981     (flush _test-output-buffered-file)
 2982 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2988     # no error; defining 'out' didn't interfere with the reclamation of 'b'
 2989     # check output
 2990     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-fn-output-written-in-inner-block/0")
 2991     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-fn-output-written-in-inner-block/1")
 2992     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-fn-output-written-in-inner-block/2")
 2993     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-fn-output-written-in-inner-block/3")
 2994     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-fn-output-written-in-inner-block/4")
 2995     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-fn-output-written-in-inner-block/5")
 2996     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-fn-output-written-in-inner-block/6")
 2997     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-fn-output-written-in-inner-block/7")
 2998     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-fn-output-written-in-inner-block/8")
 2999     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-fn-output-written-in-inner-block/9")
 3000     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-fn-output-written-in-inner-block/10")
 3001     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-fn-output-written-in-inner-block/10")
 3002     (check-next-stream-line-equal _test-output-stream "      89/<- %edi 0x00000001/r32"  "F - test-fn-output-written-in-inner-block/11")
 3003     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx"  "F - test-fn-output-written-in-inner-block/12")
 3004     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-fn-output-written-in-inner-block/13")
 3005     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-fn-output-written-in-inner-block/14")
 3006     (check-next-stream-line-equal _test-output-stream "    3d/compare-eax-with 0/imm32"  "F - test-fn-output-written-in-inner-block/15")
 3007     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-fn-output-written-in-inner-block/16")
 3008     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-fn-output-written-in-inner-block/17")
 3009     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-fn-output-written-in-inner-block/18")
 3010     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-fn-output-written-in-inner-block/19")
 3011     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-fn-output-written-in-inner-block/20")
 3012     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-fn-output-written-in-inner-block/21")
 3013     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-fn-output-written-in-inner-block/22")
 3014     # . epilogue
 3015     89/<- %esp 5/r32/ebp
 3016     5d/pop-to-ebp
 3017     c3/return
 3018 
 3019 test-convert-function-with-branches-in-block:
 3020     # . prologue
 3021     55/push-ebp
 3022     89/<- %ebp 4/r32/esp
 3023     # setup
 3024     (clear-stream _test-input-stream)
 3025     (clear-stream $_test-input-buffered-file->buffer)
 3026     (clear-stream _test-output-stream)
 3027     (clear-stream $_test-output-buffered-file->buffer)
 3028     #
 3029     (write _test-input-stream "fn foo x: int {\n")
 3030     (write _test-input-stream "  {\n")
 3031     (write _test-input-stream "    break-if->=\n")
 3032     (write _test-input-stream "    loop-if-addr<\n")
 3033     (write _test-input-stream "    increment x\n")
 3034     (write _test-input-stream "    loop\n")
 3035     (write _test-input-stream "  }\n")
 3036     (write _test-input-stream "}\n")
 3037     # convert
 3038     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3039     (flush _test-output-buffered-file)
 3040 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3046     # check output
 3047     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-block/0")
 3048     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-block/1")
 3049     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-block/2")
 3050     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-block/3")
 3051     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-block/4")
 3052     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-block/5")
 3053     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-block/6")
 3054     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-in-block/7")
 3055     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/8")
 3056     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-block/9")
 3057     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-in-block/10")
 3058     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/11")
 3059     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/12")
 3060     (check-next-stream-line-equal _test-output-stream "        0f 83/jump-if-addr>= break/disp32"  "F - test-convert-function-with-branches-in-block/13")
 3061     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:loop/disp32"  "F - test-convert-function-with-branches-in-block/14")
 3062     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/15")
 3063     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-block/16")
 3064     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-in-block/17")
 3065     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-block/18")
 3066     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-in-block/19")
 3067     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-block/20")
 3068     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-block/21")
 3069     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-block/22")
 3070     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-block/23")
 3071     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-block/24")
 3072     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-block/25")
 3073     # . epilogue
 3074     89/<- %esp 5/r32/ebp
 3075     5d/pop-to-ebp
 3076     c3/return
 3077 
 3078 test-convert-function-with-branches-in-named-block:
 3079     # . prologue
 3080     55/push-ebp
 3081     89/<- %ebp 4/r32/esp
 3082     # setup
 3083     (clear-stream _test-input-stream)
 3084     (clear-stream $_test-input-buffered-file->buffer)
 3085     (clear-stream _test-output-stream)
 3086     (clear-stream $_test-output-buffered-file->buffer)
 3087     #
 3088     (write _test-input-stream "fn foo x: int {\n")
 3089     (write _test-input-stream "  $bar: {\n")
 3090     (write _test-input-stream "    break-if->= $bar\n")
 3091     (write _test-input-stream "    loop-if-addr< $bar\n")
 3092     (write _test-input-stream "    increment x\n")
 3093     (write _test-input-stream "    loop\n")
 3094     (write _test-input-stream "  }\n")
 3095     (write _test-input-stream "}\n")
 3096     # convert
 3097     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3098     (flush _test-output-buffered-file)
 3099 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3105     # check output
 3106     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-named-block/0")
 3107     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-named-block/1")
 3108     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-named-block/2")
 3109     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-named-block/3")
 3110     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-named-block/4")
 3111     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-named-block/5")
 3112     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-named-block/6")
 3113     (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-branches-in-named-block/7")
 3114     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-named-block/8")
 3115     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-named-block/9")
 3116     (check-next-stream-line-equal _test-output-stream "        e9/jump $bar:break/disp32"  "F - test-convert-function-with-branches-in-named-block/10")
 3117     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-named-block/11")
 3118     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-named-block/12")
 3119     (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")
 3120     (check-next-stream-line-equal _test-output-stream "        e9/jump $bar:loop/disp32"  "F - test-convert-function-with-branches-in-named-block/14")
 3121     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-named-block/15")
 3122     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-named-block/16")
 3123     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"   "F - test-convert-function-with-branches-in-named-block/17")
 3124     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-named-block/18")
 3125     (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-branches-in-named-block/19")
 3126     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-named-block/20")
 3127     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-named-block/21")
 3128     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-named-block/22")
 3129     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-named-block/23")
 3130     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-named-block/24")
 3131     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-named-block/25")
 3132     # . epilogue
 3133     89/<- %esp 5/r32/ebp
 3134     5d/pop-to-ebp
 3135     c3/return
 3136 
 3137 test-convert-function-with-var-in-nested-block:
 3138     # . prologue
 3139     55/push-ebp
 3140     89/<- %ebp 4/r32/esp
 3141     # setup
 3142     (clear-stream _test-input-stream)
 3143     (clear-stream $_test-input-buffered-file->buffer)
 3144     (clear-stream _test-output-stream)
 3145     (clear-stream $_test-output-buffered-file->buffer)
 3146     #
 3147     (write _test-input-stream "fn foo x: int {\n")
 3148     (write _test-input-stream "  {\n")
 3149     (write _test-input-stream "    {\n")
 3150     (write _test-input-stream "      var x: int\n")
 3151     (write _test-input-stream "      increment x\n")
 3152     (write _test-input-stream "    }\n")
 3153     (write _test-input-stream "  }\n")
 3154     (write _test-input-stream "}\n")
 3155     # convert
 3156     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3157     (flush _test-output-buffered-file)
 3158 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3164     # check output
 3165     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-var-in-nested-block/0")
 3166     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-var-in-nested-block/1")
 3167     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-var-in-nested-block/2")
 3168     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-var-in-nested-block/3")
 3169     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-var-in-nested-block/4")
 3170     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-var-in-nested-block/5")
 3171     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-var-in-nested-block/6")
 3172     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-var-in-nested-block/7")
 3173     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-var-in-nested-block/8")
 3174     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-var-in-nested-block/9")
 3175     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-var-in-nested-block/10")
 3176     (check-next-stream-line-equal _test-output-stream "        ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-var-in-nested-block/11")
 3177     (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")
 3178     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-var-in-nested-block/13")
 3179     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-var-in-nested-block/14")
 3180     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-var-in-nested-block/15")
 3181     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-var-in-nested-block/16")
 3182     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-var-in-nested-block/17")
 3183     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-var-in-nested-block/18")
 3184     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-var-in-nested-block/19")
 3185     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-var-in-nested-block/20")
 3186     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-var-in-nested-block/21")
 3187     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-var-in-nested-block/22")
 3188     # . epilogue
 3189     89/<- %esp 5/r32/ebp
 3190     5d/pop-to-ebp
 3191     c3/return
 3192 
 3193 test-convert-function-with-multiple-vars-in-nested-blocks:
 3194     # . prologue
 3195     55/push-ebp
 3196     89/<- %ebp 4/r32/esp
 3197     # setup
 3198     (clear-stream _test-input-stream)
 3199     (clear-stream $_test-input-buffered-file->buffer)
 3200     (clear-stream _test-output-stream)
 3201     (clear-stream $_test-output-buffered-file->buffer)
 3202     #
 3203     (write _test-input-stream "fn foo x: int {\n")
 3204     (write _test-input-stream "  {\n")
 3205     (write _test-input-stream "    var x/eax: int <- copy 0\n")
 3206     (write _test-input-stream "    {\n")
 3207     (write _test-input-stream "      var y: int\n")
 3208     (write _test-input-stream "      x <- add y\n")
 3209     (write _test-input-stream "    }\n")
 3210     (write _test-input-stream "  }\n")
 3211     (write _test-input-stream "}\n")
 3212     # convert
 3213     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3214     (flush _test-output-buffered-file)
 3215 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3221     # check output
 3222     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-multiple-vars-in-nested-blocks/0")
 3223     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/1")
 3224     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-multiple-vars-in-nested-blocks/2")
 3225     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/3")
 3226     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/4")
 3227     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/5")
 3228     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/6")
 3229     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/7")
 3230     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %eax"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/8")
 3231     (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")
 3232     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/10")
 3233     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/11")
 3234     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-multiple-vars-in-nested-blocks/12")
 3235     (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")
 3236     (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")
 3237     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/15")
 3238     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/16")
 3239     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %eax"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/17")
 3240     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/18")
 3241     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/19")
 3242     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/20")
 3243     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/21")
 3244     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/22")
 3245     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/23")
 3246     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-multiple-vars-in-nested-blocks/24")
 3247     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-multiple-vars-in-nested-blocks/25")
 3248     # . epilogue
 3249     89/<- %esp 5/r32/ebp
 3250     5d/pop-to-ebp
 3251     c3/return
 3252 
 3253 test-convert-function-with-branches-and-local-vars:
 3254     # A conditional 'break' after a 'var' in a block is converted into a
 3255     # nested block that performs all necessary cleanup before jumping. This
 3256     # results in some ugly code duplication.
 3257     # . prologue
 3258     55/push-ebp
 3259     89/<- %ebp 4/r32/esp
 3260     # setup
 3261     (clear-stream _test-input-stream)
 3262     (clear-stream $_test-input-buffered-file->buffer)
 3263     (clear-stream _test-output-stream)
 3264     (clear-stream $_test-output-buffered-file->buffer)
 3265     #
 3266     (write _test-input-stream "fn foo {\n")
 3267     (write _test-input-stream "  {\n")
 3268     (write _test-input-stream "    var x: int\n")
 3269     (write _test-input-stream "    break-if->=\n")
 3270     (write _test-input-stream "    increment x\n")
 3271     (write _test-input-stream "  }\n")
 3272     (write _test-input-stream "}\n")
 3273     # convert
 3274     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3275     (flush _test-output-buffered-file)
 3276 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3282     # check output
 3283     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-local-vars/0")
 3284     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-local-vars/1")
 3285     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-local-vars/2")
 3286     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-and-local-vars/3")
 3287     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-local-vars/4")
 3288     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-local-vars/5")
 3289     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-local-vars/6")
 3290     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-local-vars/7")
 3291     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-local-vars/8")
 3292     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-local-vars/9")
 3293     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-and-local-vars/10")
 3294     (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")
 3295     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-and-local-vars/12")
 3296     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-local-vars/13")
 3297     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-branches-and-local-vars/14")
 3298     (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")
 3299     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-local-vars/16")
 3300     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-local-vars/17")
 3301     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-local-vars/18")
 3302     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-local-vars/19")
 3303     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-local-vars/20")
 3304     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-and-local-vars/21")
 3305     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-local-vars/22")
 3306     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-local-vars/23")
 3307     # . epilogue
 3308     89/<- %esp 5/r32/ebp
 3309     5d/pop-to-ebp
 3310     c3/return
 3311 
 3312 test-convert-function-with-conditional-loops-and-local-vars:
 3313     # A conditional 'loop' after a 'var' in a block is converted into a nested
 3314     # block that performs all necessary cleanup before jumping. This results
 3315     # in some ugly code duplication.
 3316     # . prologue
 3317     55/push-ebp
 3318     89/<- %ebp 4/r32/esp
 3319     # setup
 3320     (clear-stream _test-input-stream)
 3321     (clear-stream $_test-input-buffered-file->buffer)
 3322     (clear-stream _test-output-stream)
 3323     (clear-stream $_test-output-buffered-file->buffer)
 3324     #
 3325     (write _test-input-stream "fn foo {\n")
 3326     (write _test-input-stream "  {\n")
 3327     (write _test-input-stream "    var x: int\n")
 3328     (write _test-input-stream "    loop-if->=\n")
 3329     (write _test-input-stream "    increment x\n")
 3330     (write _test-input-stream "  }\n")
 3331     (write _test-input-stream "}\n")
 3332     # convert
 3333     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3334     (flush _test-output-buffered-file)
 3335 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3341     # check output
 3342     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-conditional-loops-and-local-vars/0")
 3343     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-conditional-loops-and-local-vars/1")
 3344     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-conditional-loops-and-local-vars/2")
 3345     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-conditional-loops-and-local-vars/3")
 3346     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-conditional-loops-and-local-vars/4")
 3347     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/5")
 3348     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-conditional-loops-and-local-vars/6")
 3349     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/7")
 3350     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-conditional-loops-and-local-vars/8")
 3351     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-conditional-loops-and-local-vars/9")
 3352     (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")
 3353     (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")
 3354     (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")
 3355     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-conditional-loops-and-local-vars/13")
 3356     (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")
 3357     (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")
 3358     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-conditional-loops-and-local-vars/16")
 3359     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/17")
 3360     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-conditional-loops-and-local-vars/18")
 3361     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/19")
 3362     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-conditional-loops-and-local-vars/20")
 3363     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-conditional-loops-and-local-vars/21")
 3364     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-conditional-loops-and-local-vars/22")
 3365     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-conditional-loops-and-local-vars/23")
 3366     # . epilogue
 3367     89/<- %esp 5/r32/ebp
 3368     5d/pop-to-ebp
 3369     c3/return
 3370 
 3371 test-convert-function-with-unconditional-loops-and-local-vars:
 3372     # An unconditional 'loop' after a 'var' in a block is emitted _after_ the
 3373     # regular block cleanup. Any instructions after 'loop' are dead and
 3374     # therefore skipped.
 3375     # . prologue
 3376     55/push-ebp
 3377     89/<- %ebp 4/r32/esp
 3378     # setup
 3379     (clear-stream _test-input-stream)
 3380     (clear-stream $_test-input-buffered-file->buffer)
 3381     (clear-stream _test-output-stream)
 3382     (clear-stream $_test-output-buffered-file->buffer)
 3383     #
 3384     (write _test-input-stream "fn foo {\n")
 3385     (write _test-input-stream "  {\n")
 3386     (write _test-input-stream "    var x: int\n")
 3387     (write _test-input-stream "    loop\n")
 3388     (write _test-input-stream "    increment x\n")
 3389     (write _test-input-stream "  }\n")
 3390     (write _test-input-stream "}\n")
 3391     # convert
 3392     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3393     (flush _test-output-buffered-file)
 3394 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3400     # check output
 3401     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-loops-and-local-vars/0")
 3402     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/1")
 3403     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-loops-and-local-vars/2")
 3404     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/3")
 3405     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/4")
 3406     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/5")
 3407     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/6")
 3408     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/7")
 3409     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-loops-and-local-vars/8")
 3410     (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")
 3411     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-unconditional-loops-and-local-vars/10")
 3412     # not emitted:                                           ff 0/subop/increment *(ebp+0xfffffffc)
 3413     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/11")
 3414     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/12")
 3415     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/13")
 3416     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/14")
 3417     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/15")
 3418     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/16")
 3419     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-loops-and-local-vars/17")
 3420     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-loops-and-local-vars/18")
 3421     # . epilogue
 3422     89/<- %esp 5/r32/ebp
 3423     5d/pop-to-ebp
 3424     c3/return
 3425 
 3426 test-convert-function-with-branches-and-loops-and-local-vars:
 3427     # . prologue
 3428     55/push-ebp
 3429     89/<- %ebp 4/r32/esp
 3430     # setup
 3431     (clear-stream _test-input-stream)
 3432     (clear-stream $_test-input-buffered-file->buffer)
 3433     (clear-stream _test-output-stream)
 3434     (clear-stream $_test-output-buffered-file->buffer)
 3435     #
 3436     (write _test-input-stream "fn foo {\n")
 3437     (write _test-input-stream "  {\n")
 3438     (write _test-input-stream "    var x: int\n")
 3439     (write _test-input-stream "    break-if->=\n")
 3440     (write _test-input-stream "    increment x\n")
 3441     (write _test-input-stream "    loop\n")
 3442     (write _test-input-stream "  }\n")
 3443     (write _test-input-stream "}\n")
 3444     # convert
 3445     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3446     (flush _test-output-buffered-file)
 3447 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3453     # check output
 3454     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-loops-and-local-vars/0")
 3455     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/1")
 3456     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-loops-and-local-vars/2")
 3457     (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")
 3458     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/4")
 3459     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/5")
 3460     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/6")
 3461     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/7")
 3462     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-loops-and-local-vars/8")
 3463     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/9")
 3464     (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")
 3465     (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")
 3466     (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")
 3467     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/13")
 3468     (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")
 3469     (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")
 3470     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-and-loops-and-local-vars/16")
 3471     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/17")
 3472     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/18")
 3473     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/19")
 3474     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/20")
 3475     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/21")
 3476     (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")
 3477     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-loops-and-local-vars/23")
 3478     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-loops-and-local-vars/24")
 3479     # . epilogue
 3480     89/<- %esp 5/r32/ebp
 3481     5d/pop-to-ebp
 3482     c3/return
 3483 
 3484 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars:
 3485     # . prologue
 3486     55/push-ebp
 3487     89/<- %ebp 4/r32/esp
 3488     # setup
 3489     (clear-stream _test-input-stream)
 3490     (clear-stream $_test-input-buffered-file->buffer)
 3491     (clear-stream _test-output-stream)
 3492     (clear-stream $_test-output-buffered-file->buffer)
 3493     #
 3494     (write _test-input-stream "fn foo {\n")
 3495     (write _test-input-stream "  a: {\n")
 3496     (write _test-input-stream "    var x: int\n")
 3497     (write _test-input-stream "    {\n")
 3498     (write _test-input-stream "      var y: int\n")
 3499     (write _test-input-stream "      break-if->= a\n")
 3500     (write _test-input-stream "      increment x\n")
 3501     (write _test-input-stream "      loop\n")
 3502     (write _test-input-stream "    }\n")
 3503     (write _test-input-stream "  }\n")
 3504     (write _test-input-stream "}\n")
 3505     # convert
 3506     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3507     (flush _test-output-buffered-file)
 3508 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3514     # check output
 3515     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/0")
 3516     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/1")
 3517     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/2")
 3518     (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")
 3519     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/4")
 3520     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/5")
 3521     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/6")
 3522     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/7")
 3523     (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")
 3524     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/9")
 3525     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/10")
 3526     (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")
 3527     (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/12")
 3528     (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")
 3529     (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")
 3530     (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")
 3531     (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")
 3532     (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/17")
 3533     (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")
 3534     (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")
 3535     (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")
 3536     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/21")
 3537     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/22")
 3538     (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")
 3539     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/24")
 3540     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/25")
 3541     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/26")
 3542     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/27")
 3543     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/28")
 3544     (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")
 3545     (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")
 3546     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/31")
 3547     # . epilogue
 3548     89/<- %esp 5/r32/ebp
 3549     5d/pop-to-ebp
 3550     c3/return
 3551 
 3552 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2:
 3553     # . prologue
 3554     55/push-ebp
 3555     89/<- %ebp 4/r32/esp
 3556     # setup
 3557     (clear-stream _test-input-stream)
 3558     (clear-stream $_test-input-buffered-file->buffer)
 3559     (clear-stream _test-output-stream)
 3560     (clear-stream $_test-output-buffered-file->buffer)
 3561     # non-local conditional branch from a block without a local variable,
 3562     # unwinding a local on the stack
 3563     (write _test-input-stream "fn foo {\n")
 3564     (write _test-input-stream "  a: {\n")
 3565     (write _test-input-stream "    var x: int\n")
 3566     (write _test-input-stream "    {\n")
 3567     (write _test-input-stream "      break-if->= a\n")
 3568     (write _test-input-stream "    }\n")
 3569     (write _test-input-stream "  }\n")
 3570     (write _test-input-stream "}\n")
 3571     # convert
 3572     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3573     (flush _test-output-buffered-file)
 3574 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3580     # check output
 3581     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/0")
 3582     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/1")
 3583     (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")
 3584     (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")
 3585     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/4")
 3586     (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")
 3587     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/6")
 3588     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/7")
 3589     (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")
 3590     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/9")
 3591     (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")
 3592     (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/11")
 3593     (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")
 3594     (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")
 3595     (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")
 3596     (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/15")
 3597     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/16")
 3598     (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")
 3599     (check-next-stream-line-equal _test-output-stream "      81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/18")
 3600     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/19")
 3601     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/20")
 3602     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/21")
 3603     (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")
 3604     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/23")
 3605     (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")
 3606     (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")
 3607     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/26")
 3608     # . epilogue
 3609     89/<- %esp 5/r32/ebp
 3610     5d/pop-to-ebp
 3611     c3/return
 3612 
 3613 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3:
 3614     # . prologue
 3615     55/push-ebp
 3616     89/<- %ebp 4/r32/esp
 3617     # setup
 3618     (clear-stream _test-input-stream)
 3619     (clear-stream $_test-input-buffered-file->buffer)
 3620     (clear-stream _test-output-stream)
 3621     (clear-stream $_test-output-buffered-file->buffer)
 3622     # non-local unconditional branch from a block without a local variable,
 3623     # unwinding a local on the stack
 3624     (write _test-input-stream "fn foo {\n")
 3625     (write _test-input-stream "  a: {\n")
 3626     (write _test-input-stream "    var x: int\n")
 3627     (write _test-input-stream "    {\n")
 3628     (write _test-input-stream "      break a\n")
 3629     (write _test-input-stream "    }\n")
 3630     (write _test-input-stream "  }\n")
 3631     (write _test-input-stream "}\n")
 3632     # convert
 3633     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3634     (flush _test-output-buffered-file)
 3635 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3641     # check output
 3642     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/0")
 3643     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/1")
 3644     (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")
 3645     (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")
 3646     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/4")
 3647     (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")
 3648     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/6")
 3649     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/7")
 3650     (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")
 3651     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/9")
 3652     (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")
 3653     (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")
 3654     (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")
 3655     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/14")
 3656     (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")
 3657     (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")
 3658     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/17")
 3659     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/18")
 3660     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/19")
 3661     (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")
 3662     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/21")
 3663     (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")
 3664     (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")
 3665     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/24")
 3666     # . epilogue
 3667     89/<- %esp 5/r32/ebp
 3668     5d/pop-to-ebp
 3669     c3/return
 3670 
 3671 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4:
 3672     # . prologue
 3673     55/push-ebp
 3674     89/<- %ebp 4/r32/esp
 3675     # setup
 3676     (clear-stream _test-input-stream)
 3677     (clear-stream $_test-input-buffered-file->buffer)
 3678     (clear-stream _test-output-stream)
 3679     (clear-stream $_test-output-buffered-file->buffer)
 3680     #
 3681     (write _test-input-stream "fn foo {\n")
 3682     (write _test-input-stream "  a: {\n")
 3683     (write _test-input-stream "    var x/esi: int <- copy 0\n")
 3684     (write _test-input-stream "    {\n")
 3685     (write _test-input-stream "      break a\n")
 3686     (write _test-input-stream "    }\n")
 3687     (write _test-input-stream "  }\n")
 3688     (write _test-input-stream "}\n")
 3689     # convert
 3690     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3691     (flush _test-output-buffered-file)
 3692 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3698     # check output
 3699     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/0")
 3700     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/1")
 3701     (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")
 3702     (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")
 3703     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/4")
 3704     (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")
 3705     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/6")
 3706     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/7")
 3707     (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")
 3708     (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")
 3709     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/10")
 3710     (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")
 3711     (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")
 3712     (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")
 3713     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/14")
 3714     (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")
 3715     (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")
 3716     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/17")
 3717     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/18")
 3718     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/19")
 3719     (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")
 3720     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/21")
 3721     (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")
 3722     (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")
 3723     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/24")
 3724     # . epilogue
 3725     89/<- %esp 5/r32/ebp
 3726     5d/pop-to-ebp
 3727     c3/return
 3728 
 3729 test-convert-function-with-nonlocal-unconditional-break-and-local-vars:
 3730     # . prologue
 3731     55/push-ebp
 3732     89/<- %ebp 4/r32/esp
 3733     # setup
 3734     (clear-stream _test-input-stream)
 3735     (clear-stream $_test-input-buffered-file->buffer)
 3736     (clear-stream _test-output-stream)
 3737     (clear-stream $_test-output-buffered-file->buffer)
 3738     #
 3739     (write _test-input-stream "fn foo {\n")
 3740     (write _test-input-stream "  a: {\n")
 3741     (write _test-input-stream "    var x: int\n")
 3742     (write _test-input-stream "    {\n")
 3743     (write _test-input-stream "      var y: int\n")
 3744     (write _test-input-stream "      break a\n")
 3745     (write _test-input-stream "      increment x\n")
 3746     (write _test-input-stream "    }\n")
 3747     (write _test-input-stream "  }\n")
 3748     (write _test-input-stream "}\n")
 3749     # convert
 3750     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3751     (flush _test-output-buffered-file)
 3752 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3758     # check output
 3759     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/0")
 3760     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/1")
 3761     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/2")
 3762     (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")
 3763     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/4")
 3764     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/5")
 3765     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/6")
 3766     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/7")
 3767     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/8")
 3768     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/9")
 3769     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/10")
 3770     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/11")
 3771     (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")
 3772     (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")
 3773     (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")
 3774     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/15")
 3775     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/16")
 3776     (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")
 3777     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/18")
 3778     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/19")
 3779     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/20")
 3780     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/21")
 3781     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/22")
 3782     (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")
 3783     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/24")
 3784     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/25")
 3785     # . epilogue
 3786     89/<- %esp 5/r32/ebp
 3787     5d/pop-to-ebp
 3788     c3/return
 3789 
 3790 test-convert-function-with-unconditional-break-and-local-vars:
 3791     # . prologue
 3792     55/push-ebp
 3793     89/<- %ebp 4/r32/esp
 3794     # setup
 3795     (clear-stream _test-input-stream)
 3796     (clear-stream $_test-input-buffered-file->buffer)
 3797     (clear-stream _test-output-stream)
 3798     (clear-stream $_test-output-buffered-file->buffer)
 3799     #
 3800     (write _test-input-stream "fn foo {\n")
 3801     (write _test-input-stream "  {\n")
 3802     (write _test-input-stream "    var x: int\n")
 3803     (write _test-input-stream "    {\n")
 3804     (write _test-input-stream "      var y: int\n")
 3805     (write _test-input-stream "      break\n")
 3806     (write _test-input-stream "      increment x\n")
 3807     (write _test-input-stream "    }\n")
 3808     (write _test-input-stream "  }\n")
 3809     (write _test-input-stream "}\n")
 3810     # convert
 3811     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3812     (flush _test-output-buffered-file)
 3813 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3819     # check output
 3820     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-break-and-local-vars/0")
 3821     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-break-and-local-vars/1")
 3822     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-break-and-local-vars/2")
 3823     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-break-and-local-vars/3")
 3824     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-break-and-local-vars/4")
 3825     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/5")
 3826     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-break-and-local-vars/6")
 3827     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/7")
 3828     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-break-and-local-vars/8")
 3829     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-unconditional-break-and-local-vars/9")
 3830     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/10")
 3831     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/11")
 3832     (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")
 3833     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-unconditional-break-and-local-vars/13")
 3834     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/14")
 3835     (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")
 3836     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-break-and-local-vars/16")
 3837     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/17")
 3838     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-break-and-local-vars/18")
 3839     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/19")
 3840     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-break-and-local-vars/20")
 3841     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-break-and-local-vars/21")
 3842     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-break-and-local-vars/22")
 3843     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-break-and-local-vars/23")
 3844     # . epilogue
 3845     89/<- %esp 5/r32/ebp
 3846     5d/pop-to-ebp
 3847     c3/return
 3848 
 3849 test-convert-function-with-nonlocal-unconditional-loop-and-local-vars:
 3850     # . prologue
 3851     55/push-ebp
 3852     89/<- %ebp 4/r32/esp
 3853     # setup
 3854     (clear-stream _test-input-stream)
 3855     (clear-stream $_test-input-buffered-file->buffer)
 3856     (clear-stream _test-output-stream)
 3857     (clear-stream $_test-output-buffered-file->buffer)
 3858     #
 3859     (write _test-input-stream "fn foo {\n")
 3860     (write _test-input-stream "  a: {\n")
 3861     (write _test-input-stream "    var x: int\n")
 3862     (write _test-input-stream "    {\n")
 3863     (write _test-input-stream "      var y: int\n")
 3864     (write _test-input-stream "      loop a\n")
 3865     (write _test-input-stream "      increment x\n")
 3866     (write _test-input-stream "    }\n")
 3867     (write _test-input-stream "  }\n")
 3868     (write _test-input-stream "}\n")
 3869     # convert
 3870     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3871     (flush _test-output-buffered-file)
 3872 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3878     # check output
 3879     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/0")
 3880     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/1")
 3881     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/2")
 3882     (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")
 3883     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/4")
 3884     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/5")
 3885     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/6")
 3886     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/7")
 3887     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/8")
 3888     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/9")
 3889     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/10")
 3890     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/11")
 3891     (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")
 3892     (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")
 3893     (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")
 3894     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/15")
 3895     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/16")
 3896     (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")
 3897     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/18")
 3898     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/19")
 3899     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/20")
 3900     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/21")
 3901     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/22")
 3902     (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")
 3903     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/24")
 3904     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/25")
 3905     # . epilogue
 3906     89/<- %esp 5/r32/ebp
 3907     5d/pop-to-ebp
 3908     c3/return
 3909 
 3910 test-convert-function-with-local-array-var-in-mem:
 3911     # . prologue
 3912     55/push-ebp
 3913     89/<- %ebp 4/r32/esp
 3914     # setup
 3915     (clear-stream _test-input-stream)
 3916     (clear-stream $_test-input-buffered-file->buffer)
 3917     (clear-stream _test-output-stream)
 3918     (clear-stream $_test-output-buffered-file->buffer)
 3919     #
 3920     (write _test-input-stream "fn foo {\n")
 3921     (write _test-input-stream "  var x: (array int 3)\n")
 3922     (write _test-input-stream "}\n")
 3923     # convert
 3924     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3925     (flush _test-output-buffered-file)
 3926 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3932     # check output
 3933     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-array-var-in-mem/0")
 3934     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-array-var-in-mem/1")
 3935     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-array-var-in-mem/2")
 3936     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-array-var-in-mem/3")
 3937     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-array-var-in-mem/4")
 3938     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-array-var-in-mem/5")
 3939     # define x
 3940     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-function-with-local-array-var-in-mem/7")
 3941     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-function-with-local-array-var-in-mem/8")
 3942     # reclaim x
 3943     (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")
 3944     #
 3945     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-array-var-in-mem/10")
 3946     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-array-var-in-mem/11")
 3947     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-array-var-in-mem/12")
 3948     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-array-var-in-mem/13")
 3949     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-array-var-in-mem/14")
 3950     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-array-var-in-mem/15")
 3951     # . epilogue
 3952     89/<- %esp 5/r32/ebp
 3953     5d/pop-to-ebp
 3954     c3/return
 3955 
 3956 test-array-size-in-hex:
 3957     # . prologue
 3958     55/push-ebp
 3959     89/<- %ebp 4/r32/esp
 3960     # setup
 3961     (clear-stream _test-input-stream)
 3962     (clear-stream $_test-input-buffered-file->buffer)
 3963     (clear-stream _test-output-stream)
 3964     (clear-stream $_test-output-buffered-file->buffer)
 3965     (clear-stream _test-error-stream)
 3966     (clear-stream $_test-error-buffered-file->buffer)
 3967     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 3968     68/push 0/imm32
 3969     68/push 0/imm32
 3970     89/<- %edx 4/r32/esp
 3971     (tailor-exit-descriptor %edx 0x10)
 3972     #
 3973     (write _test-input-stream "fn foo {\n")
 3974     (write _test-input-stream "  var x: (array int 10)\n")
 3975     (write _test-input-stream "}\n")
 3976     # convert
 3977     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 3978     # registers except esp clobbered at this point
 3979     # restore ed
 3980     89/<- %edx 4/r32/esp
 3981     (flush _test-output-buffered-file)
 3982     (flush _test-error-buffered-file)
 3983 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 3989     # check output
 3990     (check-stream-equal _test-output-stream  ""  "F - test-array-size-in-hex: output should be empty")
 3991     (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")
 3992     # check that stop(1) was called
 3993     (check-ints-equal *(edx+4) 2 "F - test-array-size-in-hex: exit status")
 3994     # don't restore from ebp
 3995     81 0/subop/add %esp 8/imm32
 3996     # . epilogue
 3997     5d/pop-to-ebp
 3998     c3/return
 3999 
 4000 test-convert-function-with-populate:
 4001     # . prologue
 4002     55/push-ebp
 4003     89/<- %ebp 4/r32/esp
 4004     # setup
 4005     (clear-stream _test-input-stream)
 4006     (clear-stream $_test-input-buffered-file->buffer)
 4007     (clear-stream _test-output-stream)
 4008     (clear-stream $_test-output-buffered-file->buffer)
 4009     #
 4010     (write _test-input-stream "fn foo {\n")
 4011     (write _test-input-stream "  var x/ecx: (addr handle array int) <- copy 0\n")
 4012     (write _test-input-stream "  populate x, 7\n")
 4013     (write _test-input-stream "}\n")
 4014     # convert
 4015     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4016     (flush _test-output-buffered-file)
 4017 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4023     # check output
 4024     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-populate/0")
 4025     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-populate/1")
 4026     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-populate/2")
 4027     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-populate/3")
 4028     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-populate/4")
 4029     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-populate/5")
 4030     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-populate/6")
 4031     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-populate/7")
 4032     (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)
 4033     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-populate/9")
 4034     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-populate/10")
 4035     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-populate/11")
 4036     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-populate/12")
 4037     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-populate/13")
 4038     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-populate/14")
 4039     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-populate/15")
 4040     # . epilogue
 4041     89/<- %esp 5/r32/ebp
 4042     5d/pop-to-ebp
 4043     c3/return
 4044 
 4045 # special-case for size(byte) when allocating array
 4046 test-convert-function-with-local-array-of-bytes-in-mem:
 4047     # . prologue
 4048     55/push-ebp
 4049     89/<- %ebp 4/r32/esp
 4050     # setup
 4051     (clear-stream _test-input-stream)
 4052     (clear-stream $_test-input-buffered-file->buffer)
 4053     (clear-stream _test-output-stream)
 4054     (clear-stream $_test-output-buffered-file->buffer)
 4055     #
 4056     (write _test-input-stream "fn foo {\n")
 4057     (write _test-input-stream "  var x: (array byte 3)\n")
 4058     (write _test-input-stream "}\n")
 4059     # convert
 4060     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4061     (flush _test-output-buffered-file)
 4062 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4068     # check output
 4069     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-array-of-bytes-in-mem/0")
 4070     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-array-of-bytes-in-mem/1")
 4071     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-array-of-bytes-in-mem/2")
 4072     (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")
 4073     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-array-of-bytes-in-mem/4")
 4074     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-array-of-bytes-in-mem/5")
 4075     # define x
 4076     (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")
 4077     (check-next-stream-line-equal _test-output-stream "    68/push 0x00000003/imm32"  "F - test-convert-function-with-local-array-of-bytes-in-mem/8")
 4078     # reclaim x
 4079     (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")
 4080     #
 4081     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-array-of-bytes-in-mem/10")
 4082     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-array-of-bytes-in-mem/11")
 4083     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-array-of-bytes-in-mem/12")
 4084     (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")
 4085     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-array-of-bytes-in-mem/14")
 4086     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-array-of-bytes-in-mem/15")
 4087     # . epilogue
 4088     89/<- %esp 5/r32/ebp
 4089     5d/pop-to-ebp
 4090     c3/return
 4091 
 4092 test-convert-address:
 4093     # . prologue
 4094     55/push-ebp
 4095     89/<- %ebp 4/r32/esp
 4096     # setup
 4097     (clear-stream _test-input-stream)
 4098     (clear-stream $_test-input-buffered-file->buffer)
 4099     (clear-stream _test-output-stream)
 4100     (clear-stream $_test-output-buffered-file->buffer)
 4101     #
 4102     (write _test-input-stream "fn foo {\n")
 4103     (write _test-input-stream "  var a: int\n")
 4104     (write _test-input-stream "  var b/eax: (addr int) <- address a\n")
 4105     (write _test-input-stream "}\n")
 4106     # convert
 4107     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4108     (flush _test-output-buffered-file)
 4109 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4115     # check output
 4116     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-address/0")
 4117     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-address/1")
 4118     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-address/2")
 4119     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-address/3")
 4120     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-address/4")
 4121     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-address/5")
 4122     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-address/6")
 4123     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-address/7")
 4124     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000000/r32"  "F - test-convert-address/8")
 4125     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-address/9")
 4126     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-address/10")
 4127     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-address/11")
 4128     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-address/12")
 4129     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-address/13")
 4130     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-address/14")
 4131     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-address/15")
 4132     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-address/16")
 4133     # . epilogue
 4134     89/<- %esp 5/r32/ebp
 4135     5d/pop-to-ebp
 4136     c3/return
 4137 
 4138 test-convert-length-of-array:
 4139     # . prologue
 4140     55/push-ebp
 4141     89/<- %ebp 4/r32/esp
 4142     # setup
 4143     (clear-stream _test-input-stream)
 4144     (clear-stream $_test-input-buffered-file->buffer)
 4145     (clear-stream _test-output-stream)
 4146     (clear-stream $_test-output-buffered-file->buffer)
 4147     #
 4148     (write _test-input-stream "fn foo a: (addr array int) {\n")
 4149     (write _test-input-stream "  var b/eax: (addr array int) <- copy a\n")
 4150     (write _test-input-stream "  var c/eax: int <- length b\n")
 4151     (write _test-input-stream "}\n")
 4152     # convert
 4153     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4154     (flush _test-output-buffered-file)
 4155 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4161     # check output
 4162     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array/0")
 4163     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array/1")
 4164     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array/2")
 4165     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array/3")
 4166     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array/4")
 4167     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array/5")
 4168     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array/6")
 4169     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-length-of-array/7")
 4170     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array/8")
 4171     (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array/9")
 4172     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array/10")
 4173     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array/11")
 4174     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array/12")
 4175     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array/13")
 4176     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array/14")
 4177     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array/15")
 4178     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array/16")
 4179     # . epilogue
 4180     89/<- %esp 5/r32/ebp
 4181     5d/pop-to-ebp
 4182     c3/return
 4183 
 4184 # special-case for size(byte) when computing array length
 4185 test-convert-length-of-array-of-bytes:
 4186     # . prologue
 4187     55/push-ebp
 4188     89/<- %ebp 4/r32/esp
 4189     # setup
 4190     (clear-stream _test-input-stream)
 4191     (clear-stream $_test-input-buffered-file->buffer)
 4192     (clear-stream _test-output-stream)
 4193     (clear-stream $_test-output-buffered-file->buffer)
 4194     #
 4195     (write _test-input-stream "fn foo a: (addr array byte) {\n")
 4196     (write _test-input-stream "  var b/eax: (addr array byte) <- copy a\n")
 4197     (write _test-input-stream "  var c/eax: int <- length b\n")
 4198     (write _test-input-stream "}\n")
 4199     # convert
 4200     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4201     (flush _test-output-buffered-file)
 4202 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4208     # check output
 4209     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-bytes/0")
 4210     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-bytes/1")
 4211     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-bytes/2")
 4212     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-bytes/3")
 4213     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-bytes/4")
 4214     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-bytes/5")
 4215     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-bytes/6")
 4216     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-length-of-array-of-bytes/7")
 4217     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-bytes/8")
 4218     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-bytes/9")
 4219     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-bytes/10")
 4220     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-bytes/11")
 4221     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-bytes/12")
 4222     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-bytes/13")
 4223     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-bytes/14")
 4224     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-bytes/15")
 4225     # . epilogue
 4226     89/<- %esp 5/r32/ebp
 4227     5d/pop-to-ebp
 4228     c3/return
 4229 
 4230 test-convert-length-of-array-on-stack:
 4231     # . prologue
 4232     55/push-ebp
 4233     89/<- %ebp 4/r32/esp
 4234     # setup
 4235     (clear-stream _test-input-stream)
 4236     (clear-stream $_test-input-buffered-file->buffer)
 4237     (clear-stream _test-output-stream)
 4238     (clear-stream $_test-output-buffered-file->buffer)
 4239     #
 4240     (write _test-input-stream "fn foo {\n")
 4241     (write _test-input-stream "  var a: (array int 3)\n")
 4242     (write _test-input-stream "  var b/eax: int <- length a\n")
 4243     (write _test-input-stream "}\n")
 4244     # convert
 4245     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4246     (flush _test-output-buffered-file)
 4247 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4253     # check output
 4254     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-on-stack/0")
 4255     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-on-stack/1")
 4256     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-on-stack/2")
 4257     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-on-stack/3")
 4258     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-on-stack/4")
 4259     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-on-stack/5")
 4260     # define x
 4261     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-length-of-array-on-stack/6")
 4262     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-length-of-array-on-stack/7")
 4263     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-on-stack/8")
 4264     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0xfffffff0) 0x00000000/r32"  "F - test-convert-length-of-array-on-stack/9")
 4265     (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array-on-stack/10")
 4266     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-on-stack/11")
 4267     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"  "F - test-convert-length-of-array-on-stack/12")
 4268     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-on-stack/13")
 4269     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-on-stack/14")
 4270     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-on-stack/15")
 4271     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-on-stack/16")
 4272     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-on-stack/17")
 4273     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-on-stack/18")
 4274     # . epilogue
 4275     89/<- %esp 5/r32/ebp
 4276     5d/pop-to-ebp
 4277     c3/return
 4278 
 4279 test-reg-var-def-with-read-of-same-register:
 4280     # . prologue
 4281     55/push-ebp
 4282     89/<- %ebp 4/r32/esp
 4283     # setup
 4284     (clear-stream _test-input-stream)
 4285     (clear-stream $_test-input-buffered-file->buffer)
 4286     (clear-stream _test-output-stream)
 4287     (clear-stream $_test-output-buffered-file->buffer)
 4288     (clear-stream _test-error-stream)
 4289     (clear-stream $_test-error-buffered-file->buffer)
 4290     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)  # bytes of args in call to convert-mu
 4291     68/push 0/imm32
 4292     68/push 0/imm32
 4293     89/<- %edx 4/r32/esp
 4294     (tailor-exit-descriptor %edx 0x10)
 4295     #
 4296     (write _test-input-stream "fn foo {\n")
 4297     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4298     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4299     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 4300     (write _test-input-stream "}\n")
 4301     # convert
 4302     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 4303     # registers except esp could be clobbered at this point (though they shouldn't be)
 4304     # restore ed
 4305     89/<- %edx 4/r32/esp
 4306     (flush _test-output-buffered-file)
 4307     (flush _test-error-buffered-file)
 4308 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4314     (check-stream-equal _test-error-stream  ""  "F - test-reg-var-def-with-read-of-same-register: error stream should be empty")
 4315     # check output
 4316     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-reg-var-def-with-read-of-same-register/0")
 4317     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-reg-var-def-with-read-of-same-register/1")
 4318     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-reg-var-def-with-read-of-same-register/2")
 4319     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-reg-var-def-with-read-of-same-register/3")
 4320     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-reg-var-def-with-read-of-same-register/4")
 4321     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-reg-var-def-with-read-of-same-register/5")
 4322     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-reg-var-def-with-read-of-same-register/6")
 4323     (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")
 4324     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-reg-var-def-with-read-of-same-register/8")
 4325     (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")
 4326     (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")
 4327     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-reg-var-def-with-read-of-same-register/13")
 4328     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-reg-var-def-with-read-of-same-register/14")
 4329     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-reg-var-def-with-read-of-same-register/15")
 4330     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-reg-var-def-with-read-of-same-register/16")
 4331     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-reg-var-def-with-read-of-same-register/17")
 4332     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-reg-var-def-with-read-of-same-register/18")
 4333     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-reg-var-def-with-read-of-same-register/19")
 4334     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-reg-var-def-with-read-of-same-register/20")
 4335     # don't restore from ebp
 4336     81 0/subop/add %esp 8/imm32
 4337     # . epilogue
 4338     5d/pop-to-ebp
 4339     c3/return
 4340 
 4341 test-convert-index-into-array:
 4342     # . prologue
 4343     55/push-ebp
 4344     89/<- %ebp 4/r32/esp
 4345     # setup
 4346     (clear-stream _test-input-stream)
 4347     (clear-stream $_test-input-buffered-file->buffer)
 4348     (clear-stream _test-output-stream)
 4349     (clear-stream $_test-output-buffered-file->buffer)
 4350     #
 4351     (write _test-input-stream "fn foo {\n")
 4352     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4353     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4354     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 4355     (write _test-input-stream "}\n")
 4356     # convert
 4357     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4358     (flush _test-output-buffered-file)
 4359 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4365     # check output
 4366     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array/0")
 4367     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array/1")
 4368     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array/2")
 4369     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array/3")
 4370     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array/4")
 4371     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array/5")
 4372     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array/6")
 4373     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array/7")
 4374     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array/8")
 4375     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array/9")
 4376     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx<<0x00000002 + 4) 0x00000000/r32"  "F - test-convert-index-into-array/10")
 4377     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array/11")
 4378     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array/12")
 4379     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array/13")
 4380     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array/14")
 4381     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array/15")
 4382     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array/16")
 4383     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array/17")
 4384     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array/18")
 4385     # . epilogue
 4386     89/<- %esp 5/r32/ebp
 4387     5d/pop-to-ebp
 4388     c3/return
 4389 
 4390 test-convert-index-into-array-of-bytes:
 4391     # . prologue
 4392     55/push-ebp
 4393     89/<- %ebp 4/r32/esp
 4394     # setup
 4395     (clear-stream _test-input-stream)
 4396     (clear-stream $_test-input-buffered-file->buffer)
 4397     (clear-stream _test-output-stream)
 4398     (clear-stream $_test-output-buffered-file->buffer)
 4399     #
 4400     (write _test-input-stream "fn foo {\n")
 4401     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4402     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4403     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, idx\n")
 4404     (write _test-input-stream "}\n")
 4405     # convert
 4406     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4407     (flush _test-output-buffered-file)
 4408 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4414     # check output
 4415     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes/0")
 4416     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes/1")
 4417     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes/2")
 4418     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes/3")
 4419     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes/4")
 4420     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes/5")
 4421     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes/6")
 4422     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-of-bytes/7")
 4423     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes/8")
 4424     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-of-bytes/9")
 4425     (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")
 4426     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes/13")
 4427     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes/14")
 4428     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes/15")
 4429     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes/16")
 4430     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes/17")
 4431     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes/18")
 4432     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes/19")
 4433     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes/20")
 4434     # . epilogue
 4435     89/<- %esp 5/r32/ebp
 4436     5d/pop-to-ebp
 4437     c3/return
 4438 
 4439 test-convert-index-into-array-with-literal:
 4440     # . prologue
 4441     55/push-ebp
 4442     89/<- %ebp 4/r32/esp
 4443     # setup
 4444     (clear-stream _test-input-stream)
 4445     (clear-stream $_test-input-buffered-file->buffer)
 4446     (clear-stream _test-output-stream)
 4447     (clear-stream $_test-output-buffered-file->buffer)
 4448     #
 4449     (write _test-input-stream "fn foo {\n")
 4450     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4451     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
 4452     (write _test-input-stream "}\n")
 4453     # convert
 4454     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4455     (flush _test-output-buffered-file)
 4456 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4462     # check output
 4463     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-with-literal/0")
 4464     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-with-literal/1")
 4465     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-with-literal/2")
 4466     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-with-literal/3")
 4467     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-with-literal/4")
 4468     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-with-literal/5")
 4469     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-with-literal/6")
 4470     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-with-literal/7")
 4471                                                                                  # 2 * 4 bytes/elem + 4 bytes for size = offset 12
 4472     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x0000000c) 0x00000000/r32"  "F - test-convert-index-into-array-with-literal/8")
 4473     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-with-literal/9")
 4474     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-with-literal/10")
 4475     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-with-literal/11")
 4476     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-with-literal/12")
 4477     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-with-literal/13")
 4478     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-with-literal/14")
 4479     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-with-literal/15")
 4480     # . epilogue
 4481     89/<- %esp 5/r32/ebp
 4482     5d/pop-to-ebp
 4483     c3/return
 4484 
 4485 test-convert-index-into-array-of-bytes-with-literal:
 4486     # . prologue
 4487     55/push-ebp
 4488     89/<- %ebp 4/r32/esp
 4489     # setup
 4490     (clear-stream _test-input-stream)
 4491     (clear-stream $_test-input-buffered-file->buffer)
 4492     (clear-stream _test-output-stream)
 4493     (clear-stream $_test-output-buffered-file->buffer)
 4494     #
 4495     (write _test-input-stream "fn foo {\n")
 4496     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4497     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, 2\n")
 4498     (write _test-input-stream "}\n")
 4499     # convert
 4500     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4501     (flush _test-output-buffered-file)
 4502 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4508     # check output
 4509     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-with-literal/0")
 4510     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-with-literal/1")
 4511     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-with-literal/2")
 4512     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-with-literal/3")
 4513     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-with-literal/4")
 4514     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-with-literal/5")
 4515     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-with-literal/6")
 4516     (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")
 4517                                                                                  # 2 * 1 byte/elem + 4 bytes for size = offset 6
 4518     (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")
 4519     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-with-literal/9")
 4520     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-with-literal/10")
 4521     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-with-literal/11")
 4522     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-with-literal/12")
 4523     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-with-literal/13")
 4524     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-with-literal/14")
 4525     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-with-literal/15")
 4526     # . epilogue
 4527     89/<- %esp 5/r32/ebp
 4528     5d/pop-to-ebp
 4529     c3/return
 4530 
 4531 test-convert-index-into-array-on-stack:
 4532     # . prologue
 4533     55/push-ebp
 4534     89/<- %ebp 4/r32/esp
 4535     # setup
 4536     (clear-stream _test-input-stream)
 4537     (clear-stream $_test-input-buffered-file->buffer)
 4538     (clear-stream _test-output-stream)
 4539     (clear-stream $_test-output-buffered-file->buffer)
 4540     #
 4541     (write _test-input-stream "fn foo {\n")
 4542     (write _test-input-stream "  var arr: (array int 3)\n")
 4543     (write _test-input-stream "  var idx/eax: int <- copy 2\n")
 4544     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 4545     (write _test-input-stream "}\n")
 4546     # convert
 4547     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4548     (flush _test-output-buffered-file)
 4549 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4555     # check output
 4556     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack/0")
 4557     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack/1")
 4558     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack/2")
 4559     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack/3")
 4560     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack/4")
 4561     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack/5")
 4562     # var arr
 4563     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack/6")
 4564     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack/7")
 4565     # var idx
 4566     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack/8")
 4567     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 2/imm32"                  "F - test-convert-index-into-array-on-stack/9")
 4568     # var x is at (ebp-0x10) + idx<<2 + 4 = ebp + idx<<2 - 0xc
 4569     (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")
 4570     # reclaim idx
 4571     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack/11")
 4572     # reclaim arr
 4573     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"    "F - test-convert-index-into-array-on-stack/12")
 4574     #
 4575     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack/13")
 4576     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack/14")
 4577     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack/15")
 4578     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack/16")
 4579     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack/17")
 4580     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack/18")
 4581     # . epilogue
 4582     89/<- %esp 5/r32/ebp
 4583     5d/pop-to-ebp
 4584     c3/return
 4585 
 4586 test-convert-index-into-array-on-stack-with-literal:
 4587     # . prologue
 4588     55/push-ebp
 4589     89/<- %ebp 4/r32/esp
 4590     # setup
 4591     (clear-stream _test-input-stream)
 4592     (clear-stream $_test-input-buffered-file->buffer)
 4593     (clear-stream _test-output-stream)
 4594     (clear-stream $_test-output-buffered-file->buffer)
 4595     #
 4596     (write _test-input-stream "fn foo {\n")
 4597     (write _test-input-stream "  var arr: (array int 3)\n")
 4598     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
 4599     (write _test-input-stream "}\n")
 4600     # convert
 4601     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4602     (flush _test-output-buffered-file)
 4603 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4609     # check output
 4610     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack-with-literal/0")
 4611     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack-with-literal/1")
 4612     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack-with-literal/2")
 4613     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack-with-literal/3")
 4614     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack-with-literal/4")
 4615     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack-with-literal/5")
 4616     # var arr
 4617     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack-with-literal/6")
 4618     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack-with-literal/7")
 4619     # var x
 4620     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack-with-literal/8")
 4621     # x is at (ebp-0x10) + 4 + 2*4 = ebp-4
 4622     (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")
 4623     # reclaim x
 4624     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack-with-literal/10")
 4625     # reclaim arr
 4626     (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")
 4627     #
 4628     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack-with-literal/12")
 4629     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack-with-literal/13")
 4630     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack-with-literal/14")
 4631     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack-with-literal/15")
 4632     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack-with-literal/16")
 4633     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack-with-literal/17")
 4634     # . epilogue
 4635     89/<- %esp 5/r32/ebp
 4636     5d/pop-to-ebp
 4637     c3/return
 4638 
 4639 test-convert-index-into-array-of-bytes-on-stack-with-literal:
 4640     # . prologue
 4641     55/push-ebp
 4642     89/<- %ebp 4/r32/esp
 4643     # setup
 4644     (clear-stream _test-input-stream)
 4645     (clear-stream $_test-input-buffered-file->buffer)
 4646     (clear-stream _test-output-stream)
 4647     (clear-stream $_test-output-buffered-file->buffer)
 4648     #
 4649     (write _test-input-stream "fn foo {\n")
 4650     (write _test-input-stream "  var arr: (array byte 3)\n")
 4651     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, 2\n")
 4652     (write _test-input-stream "}\n")
 4653     # convert
 4654     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4655     (flush _test-output-buffered-file)
 4656 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4662     # check output
 4663     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/0")
 4664     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/1")
 4665     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/2")
 4666     (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")
 4667     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/4")
 4668     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/5")
 4669     # var arr
 4670     (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")
 4671     (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")
 4672     # var x
 4673     (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")
 4674     # x is at (ebp-7) + 4 + 2 = ebp-1
 4675     (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")
 4676     # reclaim x
 4677     (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")
 4678     # reclaim arr
 4679     (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")
 4680     #
 4681     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/12")
 4682     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/13")
 4683     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/14")
 4684     (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")
 4685     (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")
 4686     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/17")
 4687     # . epilogue
 4688     89/<- %esp 5/r32/ebp
 4689     5d/pop-to-ebp
 4690     c3/return
 4691 
 4692 test-convert-index-into-array-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 int) <- copy 0\n")
 4704     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4705     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
 4706     (write _test-input-stream "  var x/eax: (addr int) <- 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-using-offset/0")
 4719     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset/1")
 4720     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset/2")
 4721     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset/3")
 4722     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset/4")
 4723     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset/5")
 4724     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset/6")
 4725     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-using-offset/7")
 4726     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset/8")
 4727     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-using-offset/9")
 4728     (check-next-stream-line-equal _test-output-stream "    69/multiply %ecx 0x00000004/imm32 0x00000001/r32"  "F - test-convert-index-into-array-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-using-offset/11")
 4730     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset/12")
 4731     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset/13")
 4732     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset/14")
 4733     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset/15")
 4734     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset/16")
 4735     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset/17")
 4736     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset/18")
 4737     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-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-of-bytes-using-offset:
 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 byte) <- copy 0\n")
 4755     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4756     (write _test-input-stream "  var off/ecx: (offset byte) <- compute-offset arr, idx\n")
 4757     (write _test-input-stream "  var x/eax: (addr byte) <- 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-of-bytes-using-offset/0")
 4770     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-using-offset/1")
 4771     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-using-offset/2")
 4772     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-using-offset/3")
 4773     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-using-offset/4")
 4774     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-using-offset/5")
 4775     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-using-offset/6")
 4776     (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")
 4777     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes-using-offset/8")
 4778     (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")
 4779     (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")
 4780     (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")
 4781     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes-using-offset/12")
 4782     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-using-offset/13")
 4783     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-using-offset/14")
 4784     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-using-offset/15")
 4785     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-using-offset/16")
 4786     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-using-offset/17")
 4787     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-using-offset/18")
 4788     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-using-offset/19")
 4789     # . epilogue
 4790     89/<- %esp 5/r32/ebp
 4791     5d/pop-to-ebp
 4792     c3/return
 4793 
 4794 test-convert-index-into-array-using-offset-on-stack:
 4795     # . prologue
 4796     55/push-ebp
 4797     89/<- %ebp 4/r32/esp
 4798     # setup
 4799     (clear-stream _test-input-stream)
 4800     (clear-stream $_test-input-buffered-file->buffer)
 4801     (clear-stream _test-output-stream)
 4802     (clear-stream $_test-output-buffered-file->buffer)
 4803     #
 4804     (write _test-input-stream "fn foo {\n")
 4805     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4806     (write _test-input-stream "  var idx: int\n")
 4807     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
 4808     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
 4809     (write _test-input-stream "}\n")
 4810     # convert
 4811     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4812     (flush _test-output-buffered-file)
 4813 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4819     # check output
 4820     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset-on-stack/0")
 4821     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset-on-stack/1")
 4822     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset-on-stack/2")
 4823     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset-on-stack/3")
 4824     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset-on-stack/4")
 4825     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset-on-stack/5")
 4826     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset-on-stack/6")
 4827     (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")
 4828     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"                         "F - test-convert-index-into-array-using-offset-on-stack/8")
 4829     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset-on-stack/9")
 4830     (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")
 4831     (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")
 4832     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset-on-stack/12")
 4833     (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")
 4834     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset-on-stack/14")
 4835     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset-on-stack/15")
 4836     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset-on-stack/16")
 4837     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset-on-stack/17")
 4838     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset-on-stack/18")
 4839     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset-on-stack/19")
 4840     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset-on-stack/20")
 4841     # . epilogue
 4842     89/<- %esp 5/r32/ebp
 4843     5d/pop-to-ebp
 4844     c3/return
 4845 
 4846 test-convert-index-into-array-of-bytes-using-offset-on-stack:
 4847     # . prologue
 4848     55/push-ebp
 4849     89/<- %ebp 4/r32/esp
 4850     # setup
 4851     (clear-stream _test-input-stream)
 4852     (clear-stream $_test-input-buffered-file->buffer)
 4853     (clear-stream _test-output-stream)
 4854     (clear-stream $_test-output-buffered-file->buffer)
 4855     #
 4856     (write _test-input-stream "fn foo {\n")
 4857     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4858     (write _test-input-stream "  var idx: int\n")
 4859     (write _test-input-stream "  var off/ecx: (offset byte) <- compute-offset arr, idx\n")
 4860     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, off\n")
 4861     (write _test-input-stream "}\n")
 4862     # convert
 4863     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4864     (flush _test-output-buffered-file)
 4865 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4871     # check output
 4872     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/0")
 4873     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/1")
 4874     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/2")
 4875     (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")
 4876     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/4")
 4877     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/5")
 4878     (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")
 4879     (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")
 4880     (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")
 4881     (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")
 4882     (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")
 4883     (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")
 4884     (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")
 4885     (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")
 4886     (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")
 4887     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/15")
 4888     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/16")
 4889     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/17")
 4890     (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")
 4891     (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")
 4892     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/20")
 4893     # . epilogue
 4894     89/<- %esp 5/r32/ebp
 4895     5d/pop-to-ebp
 4896     c3/return
 4897 
 4898 test-convert-function-and-type-definition:
 4899     # . prologue
 4900     55/push-ebp
 4901     89/<- %ebp 4/r32/esp
 4902     # setup
 4903     (clear-stream _test-input-stream)
 4904     (clear-stream $_test-input-buffered-file->buffer)
 4905     (clear-stream _test-output-stream)
 4906     (clear-stream $_test-output-buffered-file->buffer)
 4907     #
 4908     (write _test-input-stream "fn foo a: (addr t) {\n")
 4909     (write _test-input-stream "  var _a/eax: (addr t) <- copy a\n")
 4910     (write _test-input-stream "  var b/ecx: (addr int) <- get _a, x\n")
 4911     (write _test-input-stream "  var c/ecx: (addr int) <- get _a, y\n")
 4912     (write _test-input-stream "}\n")
 4913     (write _test-input-stream "type t {\n")
 4914     (write _test-input-stream "  x: int\n")
 4915     (write _test-input-stream "  y: int\n")
 4916     (write _test-input-stream "}\n")
 4917     # convert
 4918     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4919     (flush _test-output-buffered-file)
 4920 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4926     # check output
 4927     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-and-type-definition/0")
 4928     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-and-type-definition/1")
 4929     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-and-type-definition/2")
 4930     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-and-type-definition/3")
 4931     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-and-type-definition/4")
 4932     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-and-type-definition/5")
 4933     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-function-and-type-definition/6")
 4934     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-and-type-definition/7")
 4935     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-and-type-definition/8")
 4936     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000000) 0x00000001/r32"  "F - test-convert-function-and-type-definition/9")
 4937     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000004) 0x00000001/r32"  "F - test-convert-function-and-type-definition/11")
 4938     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-and-type-definition/13")
 4939     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-convert-function-and-type-definition/14")
 4940     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-and-type-definition/15")
 4941     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-and-type-definition/16")
 4942     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-and-type-definition/17")
 4943     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-and-type-definition/18")
 4944     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-and-type-definition/19")
 4945     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-and-type-definition/20")
 4946     # . epilogue
 4947     89/<- %esp 5/r32/ebp
 4948     5d/pop-to-ebp
 4949     c3/return
 4950 
 4951 test-type-definition-with-array:
 4952     # . prologue
 4953     55/push-ebp
 4954     89/<- %ebp 4/r32/esp
 4955     # setup
 4956     (clear-stream _test-input-stream)
 4957     (clear-stream $_test-input-buffered-file->buffer)
 4958     (clear-stream _test-output-stream)
 4959     (clear-stream $_test-output-buffered-file->buffer)
 4960     (clear-stream _test-error-stream)
 4961     (clear-stream $_test-error-buffered-file->buffer)
 4962     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 4963     68/push 0/imm32
 4964     68/push 0/imm32
 4965     89/<- %edx 4/r32/esp
 4966     (tailor-exit-descriptor %edx 0x10)
 4967     #
 4968     (write _test-input-stream "type t {\n")
 4969     (write _test-input-stream "  a: (array int 3)\n")
 4970     (write _test-input-stream "}\n")
 4971     # convert
 4972     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 4973     # registers except esp clobbered at this point
 4974     # restore ed
 4975     89/<- %edx 4/r32/esp
 4976     (flush _test-output-buffered-file)
 4977     (flush _test-error-buffered-file)
 4978 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 4984     # check output
 4985     (check-stream-equal _test-output-stream  ""  "F - test-type-definition-with-array: output should be empty")
 4986     (check-next-stream-line-equal _test-error-stream  "type t: 'array' elements not allowed for now"  "F - test-type-definition-with-array: error message")
 4987     # check that stop(1) was called
 4988     (check-ints-equal *(edx+4) 2 "F - test-type-definition-with-array: exit status")
 4989     # don't restore from ebp
 4990     81 0/subop/add %esp 8/imm32
 4991     # . epilogue
 4992     5d/pop-to-ebp
 4993     c3/return
 4994 
 4995 test-type-definition-with-addr:
 4996     # . prologue
 4997     55/push-ebp
 4998     89/<- %ebp 4/r32/esp
 4999     # setup
 5000     (clear-stream _test-input-stream)
 5001     (clear-stream $_test-input-buffered-file->buffer)
 5002     (clear-stream _test-output-stream)
 5003     (clear-stream $_test-output-buffered-file->buffer)
 5004     (clear-stream _test-error-stream)
 5005     (clear-stream $_test-error-buffered-file->buffer)
 5006     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5007     68/push 0/imm32
 5008     68/push 0/imm32
 5009     89/<- %edx 4/r32/esp
 5010     (tailor-exit-descriptor %edx 0x10)
 5011     #
 5012     (write _test-input-stream "type t {\n")
 5013     (write _test-input-stream "  a: (addr int)\n")
 5014     (write _test-input-stream "}\n")
 5015     # convert
 5016     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5017     # registers except esp clobbered at this point
 5018     # restore ed
 5019     89/<- %edx 4/r32/esp
 5020     (flush _test-output-buffered-file)
 5021     (flush _test-error-buffered-file)
 5022 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5028     # check output
 5029     (check-stream-equal _test-output-stream  ""  "F - test-type-definition-with-addr: output should be empty")
 5030     (check-next-stream-line-equal _test-error-stream  "type t: 'addr' elements not allowed"  "F - test-type-definition-with-addr: error message")
 5031     # check that stop(1) was called
 5032     (check-ints-equal *(edx+4) 2 "F - test-type-definition-with-addr: exit status")
 5033     # don't restore from ebp
 5034     81 0/subop/add %esp 8/imm32
 5035     # . epilogue
 5036     5d/pop-to-ebp
 5037     c3/return
 5038 
 5039 test-convert-function-with-local-var-with-user-defined-type:
 5040     # . prologue
 5041     55/push-ebp
 5042     89/<- %ebp 4/r32/esp
 5043     # setup
 5044     (clear-stream _test-input-stream)
 5045     (clear-stream $_test-input-buffered-file->buffer)
 5046     (clear-stream _test-output-stream)
 5047     (clear-stream $_test-output-buffered-file->buffer)
 5048     #
 5049     (write _test-input-stream "fn foo {\n")
 5050     (write _test-input-stream "  var a: t\n")
 5051     (write _test-input-stream "}\n")
 5052     (write _test-input-stream "type t {\n")
 5053     (write _test-input-stream "  x: int\n")
 5054     (write _test-input-stream "  y: int\n")
 5055     (write _test-input-stream "}\n")
 5056     # convert
 5057     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5058     (flush _test-output-buffered-file)
 5059 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5065     # check output
 5066     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-user-defined-type/0")
 5067     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-user-defined-type/1")
 5068     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-user-defined-type/2")
 5069     (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")
 5070     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-user-defined-type/4")
 5071     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-user-defined-type/5")
 5072     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/6")
 5073     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/7")
 5074     (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")
 5075     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-user-defined-type/9")
 5076     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-user-defined-type/10")
 5077     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-user-defined-type/11")
 5078     (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")
 5079     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-with-user-defined-type/13")
 5080     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-user-defined-type/14")
 5081     # . epilogue
 5082     89/<- %esp 5/r32/ebp
 5083     5d/pop-to-ebp
 5084     c3/return
 5085 
 5086 test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type:
 5087     # . prologue
 5088     55/push-ebp
 5089     89/<- %ebp 4/r32/esp
 5090     # setup
 5091     (clear-stream _test-input-stream)
 5092     (clear-stream $_test-input-buffered-file->buffer)
 5093     (clear-stream _test-output-stream)
 5094     (clear-stream $_test-output-buffered-file->buffer)
 5095     #
 5096     (write _test-input-stream "fn foo {\n")
 5097     (write _test-input-stream "  var a: t\n")
 5098     (write _test-input-stream "}\n")
 5099     (write _test-input-stream "type t {\n")
 5100     (write _test-input-stream "  x: s\n")
 5101     (write _test-input-stream "}\n")
 5102     (write _test-input-stream "type s {\n")
 5103     (write _test-input-stream "  z: int\n")
 5104     (write _test-input-stream "}\n")
 5105     # convert
 5106     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5107     (flush _test-output-buffered-file)
 5108 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5114     # check output
 5115     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/0")
 5116     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/1")
 5117     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/2")
 5118     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/3")
 5119     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/4")
 5120     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/5")
 5121     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/7")
 5122     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/8")
 5123     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/9")
 5124     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/10")
 5125     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/11")
 5126     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/12")
 5127     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/13")
 5128     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/14")
 5129     # . epilogue
 5130     89/<- %esp 5/r32/ebp
 5131     5d/pop-to-ebp
 5132     c3/return
 5133 
 5134 test-convert-function-call-with-arg-of-user-defined-type:
 5135     # . prologue
 5136     55/push-ebp
 5137     89/<- %ebp 4/r32/esp
 5138     # setup
 5139     (clear-stream _test-input-stream)
 5140     (clear-stream $_test-input-buffered-file->buffer)
 5141     (clear-stream _test-output-stream)
 5142     (clear-stream $_test-output-buffered-file->buffer)
 5143     #
 5144     (write _test-input-stream "fn f {\n")
 5145     (write _test-input-stream "  var a: t\n")
 5146     (write _test-input-stream "  foo a\n")
 5147     (write _test-input-stream "}\n")
 5148     (write _test-input-stream "fn foo x: t {\n")
 5149     (write _test-input-stream "}\n")
 5150     (write _test-input-stream "type t {\n")
 5151     (write _test-input-stream "  x: int\n")
 5152     (write _test-input-stream "  y: int\n")
 5153     (write _test-input-stream "}\n")
 5154     # convert
 5155     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5156     (flush _test-output-buffered-file)
 5157 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5163     # check output
 5164     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
 5165     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
 5166     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
 5167     (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")
 5168     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
 5169     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
 5170     # var a: t
 5171     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/6")
 5172     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/7")
 5173     # foo a
 5174     (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")
 5175     #
 5176     (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")
 5177     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
 5178     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
 5179     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
 5180     (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")
 5181     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
 5182     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
 5183     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
 5184     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
 5185     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
 5186     (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")
 5187     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
 5188     (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")
 5189     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
 5190     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
 5191     # . epilogue
 5192     89/<- %esp 5/r32/ebp
 5193     5d/pop-to-ebp
 5194     c3/return
 5195 
 5196 test-convert-function-call-with-arg-of-user-defined-type-register-indirect:
 5197     # . prologue
 5198     55/push-ebp
 5199     89/<- %ebp 4/r32/esp
 5200     # setup
 5201     (clear-stream _test-input-stream)
 5202     (clear-stream $_test-input-buffered-file->buffer)
 5203     (clear-stream _test-output-stream)
 5204     (clear-stream $_test-output-buffered-file->buffer)
 5205     #
 5206     (write _test-input-stream "fn f {\n")
 5207     (write _test-input-stream "  var a/eax: (addr t) <- copy 0\n")
 5208     (write _test-input-stream "  foo *a\n")
 5209     (write _test-input-stream "}\n")
 5210     (write _test-input-stream "fn foo x: t {\n")
 5211     (write _test-input-stream "}\n")
 5212     (write _test-input-stream "type t {\n")
 5213     (write _test-input-stream "  x: int\n")
 5214     (write _test-input-stream "  y: int\n")
 5215     (write _test-input-stream "}\n")
 5216     # convert
 5217     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5218     (flush _test-output-buffered-file)
 5219 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5225     # check output
 5226     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
 5227     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
 5228     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
 5229     (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")
 5230     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
 5231     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
 5232     # var a
 5233     (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")
 5234     (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")
 5235     # foo a
 5236     (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")
 5237     #
 5238     (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")
 5239     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
 5240     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
 5241     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
 5242     (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")
 5243     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
 5244     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
 5245     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
 5246     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
 5247     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
 5248     (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")
 5249     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
 5250     (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")
 5251     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
 5252     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
 5253     # . epilogue
 5254     89/<- %esp 5/r32/ebp
 5255     5d/pop-to-ebp
 5256     c3/return
 5257 
 5258 # we don't have special support for call-by-reference; just explicitly create
 5259 # a new variable with the address of the arg
 5260 test-convert-function-call-with-arg-of-user-defined-type-by-reference:
 5261     # . prologue
 5262     55/push-ebp
 5263     89/<- %ebp 4/r32/esp
 5264     # setup
 5265     (clear-stream _test-input-stream)
 5266     (clear-stream $_test-input-buffered-file->buffer)
 5267     (clear-stream _test-output-stream)
 5268     (clear-stream $_test-output-buffered-file->buffer)
 5269     #
 5270     (write _test-input-stream "fn f {\n")
 5271     (write _test-input-stream "  var a: t\n")
 5272     (write _test-input-stream "  var b/eax: (addr t) <- address a\n")
 5273     (write _test-input-stream "  foo b\n")
 5274     (write _test-input-stream "}\n")
 5275     (write _test-input-stream "fn foo x: (addr t) {\n")
 5276     (write _test-input-stream "  var x/ecx: (addr int) <- copy x\n")
 5277     (write _test-input-stream "  increment *x\n")
 5278     (write _test-input-stream "}\n")
 5279     (write _test-input-stream "type t {\n")
 5280     (write _test-input-stream "  x: int\n")
 5281     (write _test-input-stream "  y: int\n")
 5282     (write _test-input-stream "}\n")
 5283     # convert
 5284     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5285     (flush _test-output-buffered-file)
 5286 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5292     # check output
 5293     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/0")
 5294     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/1")
 5295     (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")
 5296     (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")
 5297     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/4")
 5298     (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")
 5299     # var a: t
 5300     (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")
 5301     (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")
 5302     # var b/eax: (addr t)
 5303     (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")
 5304     (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")
 5305     # foo a
 5306     (check-next-stream-line-equal _test-output-stream "    (foo %eax)"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/10")
 5307     #
 5308     (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")
 5309     (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")
 5310     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/13")
 5311     (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")
 5312     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/15")
 5313     (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")
 5314     (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")
 5315     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/18")
 5316     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/19")
 5317     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/20")
 5318     (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")
 5319     (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")
 5320     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/23")
 5321     (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")
 5322     (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")
 5323     (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")
 5324     (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")
 5325     (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")
 5326     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/29")
 5327     (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")
 5328     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/31")
 5329     (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")
 5330     (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")
 5331     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/34")
 5332     # . epilogue
 5333     89/<- %esp 5/r32/ebp
 5334     5d/pop-to-ebp
 5335     c3/return
 5336 
 5337 test-convert-get-on-local-variable:
 5338     # . prologue
 5339     55/push-ebp
 5340     89/<- %ebp 4/r32/esp
 5341     # setup
 5342     (clear-stream _test-input-stream)
 5343     (clear-stream $_test-input-buffered-file->buffer)
 5344     (clear-stream _test-output-stream)
 5345     (clear-stream $_test-output-buffered-file->buffer)
 5346     #
 5347     (write _test-input-stream "fn foo {\n")
 5348     (write _test-input-stream "  var a: t\n")
 5349     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5350     (write _test-input-stream "}\n")
 5351     (write _test-input-stream "type t {\n")
 5352     (write _test-input-stream "  x: int\n")
 5353     (write _test-input-stream "  y: int\n")
 5354     (write _test-input-stream "}\n")
 5355     # convert
 5356     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5357     (flush _test-output-buffered-file)
 5358 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5364     # check output
 5365     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-local-variable/0")
 5366     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-local-variable/1")
 5367     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-local-variable/2")
 5368     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-local-variable/3")
 5369     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-local-variable/4")
 5370     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-local-variable/5")
 5371     # var a
 5372     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/6")
 5373     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/7")
 5374     # var c
 5375     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-local-variable/8")
 5376     # get
 5377     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000001/r32"  "F - test-convert-get-on-local-variable/9")
 5378     # reclaim c
 5379     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-local-variable/10")
 5380     # reclaim a
 5381     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000008/imm32"  "F - test-convert-get-on-local-variable/11")
 5382     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-local-variable/12")
 5383     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-local-variable/13")
 5384     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-local-variable/14")
 5385     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-local-variable/15")
 5386     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-local-variable/16")
 5387     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-local-variable/17")
 5388     # . epilogue
 5389     89/<- %esp 5/r32/ebp
 5390     5d/pop-to-ebp
 5391     c3/return
 5392 
 5393 test-convert-get-on-function-argument:
 5394     # . prologue
 5395     55/push-ebp
 5396     89/<- %ebp 4/r32/esp
 5397     # setup
 5398     (clear-stream _test-input-stream)
 5399     (clear-stream $_test-input-buffered-file->buffer)
 5400     (clear-stream _test-output-stream)
 5401     (clear-stream $_test-output-buffered-file->buffer)
 5402     #
 5403     (write _test-input-stream "fn foo a: t {\n")
 5404     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5405     (write _test-input-stream "}\n")
 5406     (write _test-input-stream "type t {\n")
 5407     (write _test-input-stream "  x: int\n")
 5408     (write _test-input-stream "  y: int\n")
 5409     (write _test-input-stream "}\n")
 5410     # convert
 5411     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5412     (flush _test-output-buffered-file)
 5413 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5419     # check output
 5420     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument/0")
 5421     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument/1")
 5422     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument/2")
 5423     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument/3")
 5424     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument/4")
 5425     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument/5")
 5426     # var c
 5427     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument/6")
 5428     # get
 5429     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0x0000000c) 0x00000001/r32"  "F - test-convert-get-on-function-argument/7")
 5430     # reclaim c
 5431     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument/8")
 5432     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument/9")
 5433     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument/10")
 5434     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument/11")
 5435     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument/12")
 5436     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument/13")
 5437     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument/14")
 5438     # . epilogue
 5439     89/<- %esp 5/r32/ebp
 5440     5d/pop-to-ebp
 5441     c3/return
 5442 
 5443 test-convert-get-on-function-argument-with-known-type:
 5444     # . prologue
 5445     55/push-ebp
 5446     89/<- %ebp 4/r32/esp
 5447     # setup
 5448     (clear-stream _test-input-stream)
 5449     (clear-stream $_test-input-buffered-file->buffer)
 5450     (clear-stream _test-output-stream)
 5451     (clear-stream $_test-output-buffered-file->buffer)
 5452     #
 5453     (write _test-input-stream "type t {\n")
 5454     (write _test-input-stream "  x: int\n")
 5455     (write _test-input-stream "  y: int\n")
 5456     (write _test-input-stream "}\n")
 5457     (write _test-input-stream "fn foo a: t {\n")
 5458     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5459     (write _test-input-stream "}\n")
 5460     # convert
 5461     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5462     (flush _test-output-buffered-file)
 5463 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5469     # check output
 5470     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument-with-known-type/0")
 5471     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument-with-known-type/1")
 5472     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument-with-known-type/2")
 5473     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument-with-known-type/3")
 5474     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument-with-known-type/4")
 5475     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument-with-known-type/5")
 5476     # var c
 5477     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument-with-known-type/6")
 5478     # get
 5479     (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")
 5480     # reclaim c
 5481     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument-with-known-type/8")
 5482     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument-with-known-type/9")
 5483     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument-with-known-type/10")
 5484     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument-with-known-type/11")
 5485     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument-with-known-type/12")
 5486     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument-with-known-type/13")
 5487     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument-with-known-type/14")
 5488     # . epilogue
 5489     89/<- %esp 5/r32/ebp
 5490     5d/pop-to-ebp
 5491     c3/return
 5492 
 5493 test-add-with-too-many-inouts:
 5494     # . prologue
 5495     55/push-ebp
 5496     89/<- %ebp 4/r32/esp
 5497     # setup
 5498     (clear-stream _test-input-stream)
 5499     (clear-stream $_test-input-buffered-file->buffer)
 5500     (clear-stream _test-output-stream)
 5501     (clear-stream $_test-output-buffered-file->buffer)
 5502     (clear-stream _test-error-stream)
 5503     (clear-stream $_test-error-buffered-file->buffer)
 5504     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5505     68/push 0/imm32
 5506     68/push 0/imm32
 5507     89/<- %edx 4/r32/esp
 5508     (tailor-exit-descriptor %edx 0x10)
 5509     #
 5510     (write _test-input-stream "fn foo {\n")
 5511     (write _test-input-stream "  var a: int\n")
 5512     (write _test-input-stream "  var b/ecx: int <- add a, 0\n")
 5513     (write _test-input-stream "}\n")
 5514     # convert
 5515     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5516     # registers except esp clobbered at this point
 5517     # restore ed
 5518     89/<- %edx 4/r32/esp
 5519     (flush _test-output-buffered-file)
 5520     (flush _test-error-buffered-file)
 5521 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5527     # check output
 5528     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-inouts: output should be empty")
 5529     (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")
 5530     # check that stop(1) was called
 5531     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-inouts: exit status")
 5532     # don't restore from ebp
 5533     81 0/subop/add %esp 8/imm32
 5534     # . epilogue
 5535     5d/pop-to-ebp
 5536     c3/return
 5537 
 5538 test-add-with-too-many-inouts-2:
 5539     # . prologue
 5540     55/push-ebp
 5541     89/<- %ebp 4/r32/esp
 5542     # setup
 5543     (clear-stream _test-input-stream)
 5544     (clear-stream $_test-input-buffered-file->buffer)
 5545     (clear-stream _test-output-stream)
 5546     (clear-stream $_test-output-buffered-file->buffer)
 5547     (clear-stream _test-error-stream)
 5548     (clear-stream $_test-error-buffered-file->buffer)
 5549     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5550     68/push 0/imm32
 5551     68/push 0/imm32
 5552     89/<- %edx 4/r32/esp
 5553     (tailor-exit-descriptor %edx 0x10)
 5554     #
 5555     (write _test-input-stream "fn foo {\n")
 5556     (write _test-input-stream "  var a: int\n")
 5557     (write _test-input-stream "  add-to a, 0, 1\n")
 5558     (write _test-input-stream "}\n")
 5559     # convert
 5560     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5561     # registers except esp clobbered at this point
 5562     # restore ed
 5563     89/<- %edx 4/r32/esp
 5564     (flush _test-output-buffered-file)
 5565     (flush _test-error-buffered-file)
 5566 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5572     # check output
 5573     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-inouts-2: output should be empty")
 5574     (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")
 5575     # check that stop(1) was called
 5576     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-inouts-2: exit status")
 5577     # don't restore from ebp
 5578     81 0/subop/add %esp 8/imm32
 5579     # . epilogue
 5580     5d/pop-to-ebp
 5581     c3/return
 5582 
 5583 test-add-with-too-many-outputs:
 5584     # . prologue
 5585     55/push-ebp
 5586     89/<- %ebp 4/r32/esp
 5587     # setup
 5588     (clear-stream _test-input-stream)
 5589     (clear-stream $_test-input-buffered-file->buffer)
 5590     (clear-stream _test-output-stream)
 5591     (clear-stream $_test-output-buffered-file->buffer)
 5592     (clear-stream _test-error-stream)
 5593     (clear-stream $_test-error-buffered-file->buffer)
 5594     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5595     68/push 0/imm32
 5596     68/push 0/imm32
 5597     89/<- %edx 4/r32/esp
 5598     (tailor-exit-descriptor %edx 0x10)
 5599     #
 5600     (write _test-input-stream "fn foo {\n")
 5601     (write _test-input-stream "  var a/eax: int <- copy 0\n")
 5602     (write _test-input-stream "  var b/ebx: int <- copy 0\n")
 5603     (write _test-input-stream "  var c/ecx: int <- copy 0\n")
 5604     (write _test-input-stream "  c, b <- add a\n")
 5605     (write _test-input-stream "}\n")
 5606     # convert
 5607     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5608     # registers except esp clobbered at this point
 5609     # restore ed
 5610     89/<- %edx 4/r32/esp
 5611     (flush _test-output-buffered-file)
 5612     (flush _test-error-buffered-file)
 5613 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5619     # check output
 5620     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-outputs: output should be empty")
 5621     (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")
 5622     # check that stop(1) was called
 5623     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-outputs: exit status")
 5624     # don't restore from ebp
 5625     81 0/subop/add %esp 8/imm32
 5626     # . epilogue
 5627     5d/pop-to-ebp
 5628     c3/return
 5629 
 5630 test-add-with-non-number:
 5631     # . prologue
 5632     55/push-ebp
 5633     89/<- %ebp 4/r32/esp
 5634     # setup
 5635     (clear-stream _test-input-stream)
 5636     (clear-stream $_test-input-buffered-file->buffer)
 5637     (clear-stream _test-output-stream)
 5638     (clear-stream $_test-output-buffered-file->buffer)
 5639     (clear-stream _test-error-stream)
 5640     (clear-stream $_test-error-buffered-file->buffer)
 5641     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5642     68/push 0/imm32
 5643     68/push 0/imm32
 5644     89/<- %edx 4/r32/esp
 5645     (tailor-exit-descriptor %edx 0x10)
 5646     #
 5647     (write _test-input-stream "fn foo {\n")
 5648     (write _test-input-stream "  var a: int\n")
 5649     (write _test-input-stream "  var b/ecx: (addr int) <- add a\n")
 5650     (write _test-input-stream "}\n")
 5651     # convert
 5652     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5653     # registers except esp clobbered at this point
 5654     # restore ed
 5655     89/<- %edx 4/r32/esp
 5656     (flush _test-output-buffered-file)
 5657     (flush _test-error-buffered-file)
 5658 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5664     # check output
 5665     (check-stream-equal _test-output-stream  ""  "F - test-add-with-non-number: output should be empty")
 5666     (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")
 5667     # check that stop(1) was called
 5668     (check-ints-equal *(edx+4) 2 "F - test-add-with-non-number: exit status")
 5669     # don't restore from ebp
 5670     81 0/subop/add %esp 8/imm32
 5671     # . epilogue
 5672     5d/pop-to-ebp
 5673     c3/return
 5674 
 5675 test-add-with-addr-dereferenced:
 5676     # . prologue
 5677     55/push-ebp
 5678     89/<- %ebp 4/r32/esp
 5679     # setup
 5680     (clear-stream _test-input-stream)
 5681     (clear-stream $_test-input-buffered-file->buffer)
 5682     (clear-stream _test-output-stream)
 5683     (clear-stream $_test-output-buffered-file->buffer)
 5684     #
 5685     (write _test-input-stream "fn foo {\n")
 5686     (write _test-input-stream "  var a/eax: (addr int) <- copy 0\n")
 5687     (write _test-input-stream "  add-to *a, 1\n")
 5688     (write _test-input-stream "}\n")
 5689     # convert
 5690     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5691     (flush _test-output-buffered-file)
 5692     # no error
 5693     # . epilogue
 5694     89/<- %esp 5/r32/ebp
 5695     5d/pop-to-ebp
 5696     c3/return
 5697 
 5698 test-get-with-wrong-field:
 5699     # . prologue
 5700     55/push-ebp
 5701     89/<- %ebp 4/r32/esp
 5702     # setup
 5703     (clear-stream _test-input-stream)
 5704     (clear-stream $_test-input-buffered-file->buffer)
 5705     (clear-stream _test-output-stream)
 5706     (clear-stream $_test-output-buffered-file->buffer)
 5707     (clear-stream _test-error-stream)
 5708     (clear-stream $_test-error-buffered-file->buffer)
 5709     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5710     68/push 0/imm32
 5711     68/push 0/imm32
 5712     89/<- %edx 4/r32/esp
 5713     (tailor-exit-descriptor %edx 0x10)
 5714     #
 5715     (write _test-input-stream "fn foo {\n")
 5716     (write _test-input-stream "  var a: t\n")
 5717     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5718     (write _test-input-stream "}\n")
 5719     (write _test-input-stream "type t {\n")
 5720     (write _test-input-stream "  x: int\n")
 5721     (write _test-input-stream "}\n")
 5722     # convert
 5723     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5724     # registers except esp clobbered at this point
 5725     # restore ed
 5726     89/<- %edx 4/r32/esp
 5727     (flush _test-output-buffered-file)
 5728     (flush _test-error-buffered-file)
 5729 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5735     # check output
 5736     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-field: output should be empty")
 5737     (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")
 5738     # check that stop(1) was called
 5739     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-field: exit status")
 5740     # don't restore from ebp
 5741     81 0/subop/add %esp 8/imm32
 5742     # . epilogue
 5743     5d/pop-to-ebp
 5744     c3/return
 5745 
 5746 test-get-with-wrong-base-type:
 5747     # . prologue
 5748     55/push-ebp
 5749     89/<- %ebp 4/r32/esp
 5750     # setup
 5751     (clear-stream _test-input-stream)
 5752     (clear-stream $_test-input-buffered-file->buffer)
 5753     (clear-stream _test-output-stream)
 5754     (clear-stream $_test-output-buffered-file->buffer)
 5755     (clear-stream _test-error-stream)
 5756     (clear-stream $_test-error-buffered-file->buffer)
 5757     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5758     68/push 0/imm32
 5759     68/push 0/imm32
 5760     89/<- %edx 4/r32/esp
 5761     (tailor-exit-descriptor %edx 0x10)
 5762     #
 5763     (write _test-input-stream "fn foo {\n")
 5764     (write _test-input-stream "  var a: int\n")
 5765     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5766     (write _test-input-stream "}\n")
 5767     # convert
 5768     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5769     # registers except esp clobbered at this point
 5770     # restore ed
 5771     89/<- %edx 4/r32/esp
 5772     (flush _test-output-buffered-file)
 5773     (flush _test-error-buffered-file)
 5774 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5780     # check output
 5781     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-base-type: output should be empty")
 5782     (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")
 5783     # check that stop(1) was called
 5784     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-base-type: exit status")
 5785     # don't restore from ebp
 5786     81 0/subop/add %esp 8/imm32
 5787     # . epilogue
 5788     5d/pop-to-ebp
 5789     c3/return
 5790 
 5791 test-get-with-wrong-base-type-2:
 5792     # . prologue
 5793     55/push-ebp
 5794     89/<- %ebp 4/r32/esp
 5795     # setup
 5796     (clear-stream _test-input-stream)
 5797     (clear-stream $_test-input-buffered-file->buffer)
 5798     (clear-stream _test-output-stream)
 5799     (clear-stream $_test-output-buffered-file->buffer)
 5800     (clear-stream _test-error-stream)
 5801     (clear-stream $_test-error-buffered-file->buffer)
 5802     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5803     68/push 0/imm32
 5804     68/push 0/imm32
 5805     89/<- %edx 4/r32/esp
 5806     (tailor-exit-descriptor %edx 0x10)
 5807     #
 5808     (write _test-input-stream "fn foo {\n")
 5809     (write _test-input-stream "  var a: (addr t)\n")
 5810     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5811     (write _test-input-stream "}\n")
 5812     (write _test-input-stream "type t {\n")
 5813     (write _test-input-stream "  x: int\n")
 5814     (write _test-input-stream "}\n")
 5815     # convert
 5816     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5817     # registers except esp clobbered at this point
 5818     # restore ed
 5819     89/<- %edx 4/r32/esp
 5820     (flush _test-output-buffered-file)
 5821     (flush _test-error-buffered-file)
 5822 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5828     # check output
 5829     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-base-type-2: output should be empty")
 5830     (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")
 5831     # check that stop(1) was called
 5832     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-base-type-2: exit status")
 5833     # don't restore from ebp
 5834     81 0/subop/add %esp 8/imm32
 5835     # . epilogue
 5836     5d/pop-to-ebp
 5837     c3/return
 5838 
 5839 test-get-with-wrong-offset-type:
 5840     # . prologue
 5841     55/push-ebp
 5842     89/<- %ebp 4/r32/esp
 5843     # setup
 5844     (clear-stream _test-input-stream)
 5845     (clear-stream $_test-input-buffered-file->buffer)
 5846     (clear-stream _test-output-stream)
 5847     (clear-stream $_test-output-buffered-file->buffer)
 5848     (clear-stream _test-error-stream)
 5849     (clear-stream $_test-error-buffered-file->buffer)
 5850     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5851     68/push 0/imm32
 5852     68/push 0/imm32
 5853     89/<- %edx 4/r32/esp
 5854     (tailor-exit-descriptor %edx 0x10)
 5855     #
 5856     (write _test-input-stream "fn foo {\n")
 5857     (write _test-input-stream "  var a: t\n")
 5858     (write _test-input-stream "  var b: int\n")
 5859     (write _test-input-stream "  var c/ecx: (addr int) <- get a, b\n")
 5860     (write _test-input-stream "}\n")
 5861     (write _test-input-stream "type t {\n")
 5862     (write _test-input-stream "  x: int\n")
 5863     (write _test-input-stream "}\n")
 5864     # convert
 5865     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5866     # registers except esp clobbered at this point
 5867     # restore ed
 5868     89/<- %edx 4/r32/esp
 5869     (flush _test-output-buffered-file)
 5870     (flush _test-error-buffered-file)
 5871 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5877     # check output
 5878     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-offset-type: output should be empty")
 5879     (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")
 5880     # check that stop(1) was called
 5881     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-offset-type: exit status")
 5882     # don't restore from ebp
 5883     81 0/subop/add %esp 8/imm32
 5884     # . epilogue
 5885     5d/pop-to-ebp
 5886     c3/return
 5887 
 5888 test-get-with-wrong-output-type:
 5889     # . prologue
 5890     55/push-ebp
 5891     89/<- %ebp 4/r32/esp
 5892     # setup
 5893     (clear-stream _test-input-stream)
 5894     (clear-stream $_test-input-buffered-file->buffer)
 5895     (clear-stream _test-output-stream)
 5896     (clear-stream $_test-output-buffered-file->buffer)
 5897     (clear-stream _test-error-stream)
 5898     (clear-stream $_test-error-buffered-file->buffer)
 5899     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5900     68/push 0/imm32
 5901     68/push 0/imm32
 5902     89/<- %edx 4/r32/esp
 5903     (tailor-exit-descriptor %edx 0x10)
 5904     #
 5905     (write _test-input-stream "fn foo {\n")
 5906     (write _test-input-stream "  var a: t\n")
 5907     (write _test-input-stream "  var c: (addr int)\n")
 5908     (write _test-input-stream "  c <- get a, x\n")
 5909     (write _test-input-stream "}\n")
 5910     (write _test-input-stream "type t {\n")
 5911     (write _test-input-stream "  x: int\n")
 5912     (write _test-input-stream "}\n")
 5913     # convert
 5914     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5915     # registers except esp clobbered at this point
 5916     # restore ed
 5917     89/<- %edx 4/r32/esp
 5918     (flush _test-output-buffered-file)
 5919     (flush _test-error-buffered-file)
 5920 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5926     # check output
 5927     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type: output should be empty")
 5928     (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")
 5929     # check that stop(1) was called
 5930     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type: exit status")
 5931     # don't restore from ebp
 5932     81 0/subop/add %esp 8/imm32
 5933     # . epilogue
 5934     5d/pop-to-ebp
 5935     c3/return
 5936 
 5937 test-get-with-wrong-output-type-2:
 5938     # . prologue
 5939     55/push-ebp
 5940     89/<- %ebp 4/r32/esp
 5941     # setup
 5942     (clear-stream _test-input-stream)
 5943     (clear-stream $_test-input-buffered-file->buffer)
 5944     (clear-stream _test-output-stream)
 5945     (clear-stream $_test-output-buffered-file->buffer)
 5946     (clear-stream _test-error-stream)
 5947     (clear-stream $_test-error-buffered-file->buffer)
 5948     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5949     68/push 0/imm32
 5950     68/push 0/imm32
 5951     89/<- %edx 4/r32/esp
 5952     (tailor-exit-descriptor %edx 0x10)
 5953     #
 5954     (write _test-input-stream "fn foo {\n")
 5955     (write _test-input-stream "  var a: t\n")
 5956     (write _test-input-stream "  var c/ecx: int <- get a, x\n")
 5957     (write _test-input-stream "}\n")
 5958     (write _test-input-stream "type t {\n")
 5959     (write _test-input-stream "  x: int\n")
 5960     (write _test-input-stream "}\n")
 5961     # convert
 5962     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5963     # registers except esp clobbered at this point
 5964     # restore ed
 5965     89/<- %edx 4/r32/esp
 5966     (flush _test-output-buffered-file)
 5967     (flush _test-error-buffered-file)
 5968 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5974     # check output
 5975     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-2: output should be empty")
 5976     (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")
 5977     # check that stop(1) was called
 5978     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-2: exit status")
 5979     # don't restore from ebp
 5980     81 0/subop/add %esp 8/imm32
 5981     # . epilogue
 5982     5d/pop-to-ebp
 5983     c3/return
 5984 
 5985 test-get-with-wrong-output-type-3:
 5986     # . prologue
 5987     55/push-ebp
 5988     89/<- %ebp 4/r32/esp
 5989     # setup
 5990     (clear-stream _test-input-stream)
 5991     (clear-stream $_test-input-buffered-file->buffer)
 5992     (clear-stream _test-output-stream)
 5993     (clear-stream $_test-output-buffered-file->buffer)
 5994     (clear-stream _test-error-stream)
 5995     (clear-stream $_test-error-buffered-file->buffer)
 5996     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5997     68/push 0/imm32
 5998     68/push 0/imm32
 5999     89/<- %edx 4/r32/esp
 6000     (tailor-exit-descriptor %edx 0x10)
 6001     #
 6002     (write _test-input-stream "fn foo {\n")
 6003     (write _test-input-stream "  var a: t\n")
 6004     (write _test-input-stream "  var c/ecx: (array int) <- get a, x\n")
 6005     (write _test-input-stream "}\n")
 6006     (write _test-input-stream "type t {\n")
 6007     (write _test-input-stream "  x: int\n")
 6008     (write _test-input-stream "}\n")
 6009     # convert
 6010     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6011     # registers except esp clobbered at this point
 6012     # restore ed
 6013     89/<- %edx 4/r32/esp
 6014     (flush _test-output-buffered-file)
 6015     (flush _test-error-buffered-file)
 6016 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6022     # check output
 6023     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-3: output should be empty")
 6024     (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")
 6025     # check that stop(1) was called
 6026     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-3: exit status")
 6027     # don't restore from ebp
 6028     81 0/subop/add %esp 8/imm32
 6029     # . epilogue
 6030     5d/pop-to-ebp
 6031     c3/return
 6032 
 6033 test-get-with-wrong-output-type-4:
 6034     # . prologue
 6035     55/push-ebp
 6036     89/<- %ebp 4/r32/esp
 6037     # setup
 6038     (clear-stream _test-input-stream)
 6039     (clear-stream $_test-input-buffered-file->buffer)
 6040     (clear-stream _test-output-stream)
 6041     (clear-stream $_test-output-buffered-file->buffer)
 6042     (clear-stream _test-error-stream)
 6043     (clear-stream $_test-error-buffered-file->buffer)
 6044     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6045     68/push 0/imm32
 6046     68/push 0/imm32
 6047     89/<- %edx 4/r32/esp
 6048     (tailor-exit-descriptor %edx 0x10)
 6049     #
 6050     (write _test-input-stream "fn foo {\n")
 6051     (write _test-input-stream "  var a: t\n")
 6052     (write _test-input-stream "  var c/ecx: (addr boolean) <- get a, x\n")
 6053     (write _test-input-stream "}\n")
 6054     (write _test-input-stream "type t {\n")
 6055     (write _test-input-stream "  x: int\n")
 6056     (write _test-input-stream "}\n")
 6057     # convert
 6058     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6059     # registers except esp clobbered at this point
 6060     # restore ed
 6061     89/<- %edx 4/r32/esp
 6062     (flush _test-output-buffered-file)
 6063     (flush _test-error-buffered-file)
 6064 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6070     # check output
 6071     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-4: output should be empty")
 6072     (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")
 6073     # check that stop(1) was called
 6074     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-4: exit status")
 6075     # don't restore from ebp
 6076     81 0/subop/add %esp 8/imm32
 6077     # . epilogue
 6078     5d/pop-to-ebp
 6079     c3/return
 6080 
 6081 test-get-with-wrong-output-type-5:
 6082     # . prologue
 6083     55/push-ebp
 6084     89/<- %ebp 4/r32/esp
 6085     # setup
 6086     (clear-stream _test-input-stream)
 6087     (clear-stream $_test-input-buffered-file->buffer)
 6088     (clear-stream _test-output-stream)
 6089     (clear-stream $_test-output-buffered-file->buffer)
 6090     #
 6091     (write _test-input-stream "fn foo {\n")
 6092     (write _test-input-stream "  var a: t\n")
 6093     (write _test-input-stream "  var c/ecx: (addr handle int) <- get a, x\n")
 6094     (write _test-input-stream "}\n")
 6095     (write _test-input-stream "type t {\n")
 6096     (write _test-input-stream "  x: (handle int)\n")
 6097     (write _test-input-stream "}\n")
 6098     # convert
 6099     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6100     (flush _test-output-buffered-file)
 6101     # no errors
 6102     # . epilogue
 6103     89/<- %esp 5/r32/ebp
 6104     5d/pop-to-ebp
 6105     c3/return
 6106 
 6107 test-get-with-too-few-inouts:
 6108     # . prologue
 6109     55/push-ebp
 6110     89/<- %ebp 4/r32/esp
 6111     # setup
 6112     (clear-stream _test-input-stream)
 6113     (clear-stream $_test-input-buffered-file->buffer)
 6114     (clear-stream _test-output-stream)
 6115     (clear-stream $_test-output-buffered-file->buffer)
 6116     (clear-stream _test-error-stream)
 6117     (clear-stream $_test-error-buffered-file->buffer)
 6118     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6119     68/push 0/imm32
 6120     68/push 0/imm32
 6121     89/<- %edx 4/r32/esp
 6122     (tailor-exit-descriptor %edx 0x10)
 6123     #
 6124     (write _test-input-stream "fn foo {\n")
 6125     (write _test-input-stream "  var a: t\n")
 6126     (write _test-input-stream "  var c/ecx: (addr int) <- get a\n")
 6127     (write _test-input-stream "}\n")
 6128     (write _test-input-stream "type t {\n")
 6129     (write _test-input-stream "  x: int\n")
 6130     (write _test-input-stream "}\n")
 6131     # convert
 6132     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6133     # registers except esp clobbered at this point
 6134     # restore ed
 6135     89/<- %edx 4/r32/esp
 6136     (flush _test-output-buffered-file)
 6137     (flush _test-error-buffered-file)
 6138 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6144     # check output
 6145     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-few-inouts: output should be empty")
 6146     (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")
 6147     # check that stop(1) was called
 6148     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-few-inouts: exit status")
 6149     # don't restore from ebp
 6150     81 0/subop/add %esp 8/imm32
 6151     # . epilogue
 6152     5d/pop-to-ebp
 6153     c3/return
 6154 
 6155 test-get-with-too-many-inouts:
 6156     # . prologue
 6157     55/push-ebp
 6158     89/<- %ebp 4/r32/esp
 6159     # setup
 6160     (clear-stream _test-input-stream)
 6161     (clear-stream $_test-input-buffered-file->buffer)
 6162     (clear-stream _test-output-stream)
 6163     (clear-stream $_test-output-buffered-file->buffer)
 6164     (clear-stream _test-error-stream)
 6165     (clear-stream $_test-error-buffered-file->buffer)
 6166     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6167     68/push 0/imm32
 6168     68/push 0/imm32
 6169     89/<- %edx 4/r32/esp
 6170     (tailor-exit-descriptor %edx 0x10)
 6171     #
 6172     (write _test-input-stream "fn foo {\n")
 6173     (write _test-input-stream "  var a: t\n")
 6174     (write _test-input-stream "  var c/ecx: (addr int) <- get a, x, 0\n")
 6175     (write _test-input-stream "}\n")
 6176     (write _test-input-stream "type t {\n")
 6177     (write _test-input-stream "  x: int\n")
 6178     (write _test-input-stream "}\n")
 6179     # convert
 6180     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6181     # registers except esp clobbered at this point
 6182     # restore ed
 6183     89/<- %edx 4/r32/esp
 6184     (flush _test-output-buffered-file)
 6185     (flush _test-error-buffered-file)
 6186 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6192     # check output
 6193     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-many-inouts: output should be empty")
 6194     (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")
 6195     # check that stop(1) was called
 6196     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-many-inouts: exit status")
 6197     # don't restore from ebp
 6198     81 0/subop/add %esp 8/imm32
 6199     # . epilogue
 6200     5d/pop-to-ebp
 6201     c3/return
 6202 
 6203 test-get-with-no-output:
 6204     # . prologue
 6205     55/push-ebp
 6206     89/<- %ebp 4/r32/esp
 6207     # setup
 6208     (clear-stream _test-input-stream)
 6209     (clear-stream $_test-input-buffered-file->buffer)
 6210     (clear-stream _test-output-stream)
 6211     (clear-stream $_test-output-buffered-file->buffer)
 6212     (clear-stream _test-error-stream)
 6213     (clear-stream $_test-error-buffered-file->buffer)
 6214     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6215     68/push 0/imm32
 6216     68/push 0/imm32
 6217     89/<- %edx 4/r32/esp
 6218     (tailor-exit-descriptor %edx 0x10)
 6219     #
 6220     (write _test-input-stream "fn foo {\n")
 6221     (write _test-input-stream "  var a: t\n")
 6222     (write _test-input-stream "  get a, x\n")
 6223     (write _test-input-stream "}\n")
 6224     (write _test-input-stream "type t {\n")
 6225     (write _test-input-stream "  x: int\n")
 6226     (write _test-input-stream "}\n")
 6227     # convert
 6228     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6229     # registers except esp clobbered at this point
 6230     # restore ed
 6231     89/<- %edx 4/r32/esp
 6232     (flush _test-output-buffered-file)
 6233     (flush _test-error-buffered-file)
 6234 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6240     # check output
 6241     (check-stream-equal _test-output-stream  ""  "F - test-get-with-no-output: output should be empty")
 6242     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: must have an output"  "F - test-get-with-no-output: error message")
 6243     # check that stop(1) was called
 6244     (check-ints-equal *(edx+4) 2 "F - test-get-with-no-output: exit status")
 6245     # don't restore from ebp
 6246     81 0/subop/add %esp 8/imm32
 6247     # . epilogue
 6248     5d/pop-to-ebp
 6249     c3/return
 6250 
 6251 test-get-with-too-many-outputs:
 6252     # . prologue
 6253     55/push-ebp
 6254     89/<- %ebp 4/r32/esp
 6255     # setup
 6256     (clear-stream _test-input-stream)
 6257     (clear-stream $_test-input-buffered-file->buffer)
 6258     (clear-stream _test-output-stream)
 6259     (clear-stream $_test-output-buffered-file->buffer)
 6260     (clear-stream _test-error-stream)
 6261     (clear-stream $_test-error-buffered-file->buffer)
 6262     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6263     68/push 0/imm32
 6264     68/push 0/imm32
 6265     89/<- %edx 4/r32/esp
 6266     (tailor-exit-descriptor %edx 0x10)
 6267     #
 6268     (write _test-input-stream "fn foo {\n")
 6269     (write _test-input-stream "  var a: t\n")
 6270     (write _test-input-stream "  var b: int\n")
 6271     (write _test-input-stream "  var c/eax: (addr int) <- copy 0\n")
 6272     (write _test-input-stream "  c, b <- get a, x\n")
 6273     (write _test-input-stream "}\n")
 6274     (write _test-input-stream "type t {\n")
 6275     (write _test-input-stream "  x: int\n")
 6276     (write _test-input-stream "}\n")
 6277     # convert
 6278     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6279     # registers except esp clobbered at this point
 6280     # restore ed
 6281     89/<- %edx 4/r32/esp
 6282     (flush _test-output-buffered-file)
 6283     (flush _test-error-buffered-file)
 6284 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6290     # check output
 6291     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-many-outputs: output should be empty")
 6292     (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")
 6293     # check that stop(1) was called
 6294     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-many-outputs: exit status")
 6295     # don't restore from ebp
 6296     81 0/subop/add %esp 8/imm32
 6297     # . epilogue
 6298     5d/pop-to-ebp
 6299     c3/return
 6300 
 6301 test-convert-array-of-user-defined-types:
 6302     # . prologue
 6303     55/push-ebp
 6304     89/<- %ebp 4/r32/esp
 6305     # setup
 6306     (clear-stream _test-input-stream)
 6307     (clear-stream $_test-input-buffered-file->buffer)
 6308     (clear-stream _test-output-stream)
 6309     (clear-stream $_test-output-buffered-file->buffer)
 6310     #
 6311     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
 6312     (write _test-input-stream "  x: int\n")
 6313     (write _test-input-stream "  y: int\n")
 6314     (write _test-input-stream "}\n")
 6315     (write _test-input-stream "fn foo {\n")
 6316     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6317     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 6318     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 6319     (write _test-input-stream "}\n")
 6320     # convert
 6321     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6322     (flush _test-output-buffered-file)
 6323 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 6329     # check output
 6330     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-array-of-user-defined-types/0")
 6331     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-array-of-user-defined-types/1")
 6332     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-array-of-user-defined-types/2")
 6333     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-array-of-user-defined-types/3")
 6334     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-array-of-user-defined-types/4")
 6335     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-array-of-user-defined-types/5")
 6336     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-array-of-user-defined-types/6")
 6337     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-array-of-user-defined-types/7")
 6338     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-array-of-user-defined-types/8")
 6339     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-array-of-user-defined-types/9")
 6340     (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")
 6341     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-array-of-user-defined-types/13")
 6342     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-array-of-user-defined-types/14")
 6343     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-array-of-user-defined-types/15")
 6344     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-array-of-user-defined-types/16")
 6345     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-array-of-user-defined-types/17")
 6346     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-array-of-user-defined-types/18")
 6347     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-array-of-user-defined-types/19")
 6348     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-array-of-user-defined-types/20")
 6349     # . epilogue
 6350     89/<- %esp 5/r32/ebp
 6351     5d/pop-to-ebp
 6352     c3/return
 6353 
 6354 test-convert-length-of-array-of-user-defined-types-to-eax:
 6355     # . prologue
 6356     55/push-ebp
 6357     89/<- %ebp 4/r32/esp
 6358     # setup
 6359     (clear-stream _test-input-stream)
 6360     (clear-stream $_test-input-buffered-file->buffer)
 6361     (clear-stream _test-output-stream)
 6362     (clear-stream $_test-output-buffered-file->buffer)
 6363     #
 6364     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 6365     (write _test-input-stream "  x: int\n")
 6366     (write _test-input-stream "  y: int\n")
 6367     (write _test-input-stream "  z: int\n")
 6368     (write _test-input-stream "}\n")
 6369     (write _test-input-stream "fn foo {\n")
 6370     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6371     (write _test-input-stream "  var x/eax: (addr t) <- length arr\n")
 6372     (write _test-input-stream "}\n")
 6373     # convert
 6374     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6375     (flush _test-output-buffered-file)
 6376 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 6382     # check output
 6383     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-eax/0")
 6384     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/1")
 6385     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-eax/2")
 6386     (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")
 6387     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/4")
 6388     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-eax/5")
 6389     # var arr
 6390     (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")
 6391     (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")
 6392     # length instruction
 6393     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/8")
 6394     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/9")
 6395     (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")
 6396     (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")
 6397     (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")
 6398     (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")
 6399     (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")
 6400     (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")
 6401     # reclaim arr
 6402     (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")
 6403     #
 6404     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/17")
 6405     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/18")
 6406     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/19")
 6407     (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")
 6408     (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")
 6409     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-eax/22")
 6410     # . epilogue
 6411     89/<- %esp 5/r32/ebp
 6412     5d/pop-to-ebp
 6413     c3/return
 6414 
 6415 test-convert-length-of-array-of-user-defined-types-to-ecx:
 6416     # . prologue
 6417     55/push-ebp
 6418     89/<- %ebp 4/r32/esp
 6419     # setup
 6420     (clear-stream _test-input-stream)
 6421     (clear-stream $_test-input-buffered-file->buffer)
 6422     (clear-stream _test-output-stream)
 6423     (clear-stream $_test-output-buffered-file->buffer)
 6424     #
 6425     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 6426     (write _test-input-stream "  x: int\n")
 6427     (write _test-input-stream "  y: int\n")
 6428     (write _test-input-stream "  z: int\n")
 6429     (write _test-input-stream "}\n")
 6430     (write _test-input-stream "fn foo {\n")
 6431     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6432     (write _test-input-stream "  var x/ecx: (addr t) <- length arr\n")
 6433     (write _test-input-stream "}\n")
 6434     # convert
 6435     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6436     (flush _test-output-buffered-file)
 6437 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 6443     # check output
 6444     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-ecx/0")
 6445     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/1")
 6446     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-ecx/2")
 6447     (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")
 6448     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/4")
 6449     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-ecx/5")
 6450     # var a
 6451     (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")
 6452     (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")
 6453     # var x
 6454     (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")
 6455     # length instruction
 6456     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/9")
 6457     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/10")
 6458     (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")
 6459     (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")
 6460     (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")
 6461     (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")
 6462     (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")
 6463     (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")
 6464     (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")
 6465     # reclaim x
 6466     (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")
 6467     # reclaim a
 6468     (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")
 6469     #
 6470     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/20")
 6471     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/21")
 6472     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/22")
 6473     (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")
 6474     (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")
 6475     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-ecx/25")
 6476     # . epilogue
 6477     89/<- %esp 5/r32/ebp
 6478     5d/pop-to-ebp
 6479     c3/return
 6480 
 6481 test-convert-length-of-array-of-user-defined-types-to-edx:
 6482     # . prologue
 6483     55/push-ebp
 6484     89/<- %ebp 4/r32/esp
 6485     # setup
 6486     (clear-stream _test-input-stream)
 6487     (clear-stream $_test-input-buffered-file->buffer)
 6488     (clear-stream _test-output-stream)
 6489     (clear-stream $_test-output-buffered-file->buffer)
 6490     #
 6491     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 6492     (write _test-input-stream "  x: int\n")
 6493     (write _test-input-stream "  y: int\n")
 6494     (write _test-input-stream "  z: int\n")
 6495     (write _test-input-stream "}\n")
 6496     (write _test-input-stream "fn foo {\n")
 6497     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6498     (write _test-input-stream "  var x/edx: (addr t) <- length arr\n")
 6499     (write _test-input-stream "}\n")
 6500     # convert
 6501     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6502     (flush _test-output-buffered-file)
 6503 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 6509     # check output
 6510     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-edx/0")
 6511     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/1")
 6512     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-edx/2")
 6513     (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")
 6514     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/4")
 6515     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-edx/5")
 6516     # var a
 6517     (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")
 6518     (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")
 6519     # var x
 6520     (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")
 6521     # length instruction
 6522     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/9")
 6523     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/10")
 6524     (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")
 6525     (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")
 6526     (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")
 6527     (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")
 6528     (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")
 6529     (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")
 6530     (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")
 6531     # reclaim x
 6532     (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")
 6533     # reclaim a
 6534     (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")
 6535     #
 6536     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/20")
 6537     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/21")
 6538     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/22")
 6539     (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")
 6540     (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")
 6541     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-edx/25")
 6542     # . epilogue
 6543     89/<- %esp 5/r32/ebp
 6544     5d/pop-to-ebp
 6545     c3/return
 6546 
 6547 test-convert-length-of-array-of-user-defined-types:
 6548     # . prologue
 6549     55/push-ebp
 6550     89/<- %ebp 4/r32/esp
 6551     # setup
 6552     (clear-stream _test-input-stream)
 6553     (clear-stream $_test-input-buffered-file->buffer)
 6554     (clear-stream _test-output-stream)
 6555     (clear-stream $_test-output-buffered-file->buffer)
 6556     #
 6557     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
 6558     (write _test-input-stream "  x: int\n")
 6559     (write _test-input-stream "  y: int\n")
 6560     (write _test-input-stream "  z: int\n")
 6561     (write _test-input-stream "}\n")
 6562     (write _test-input-stream "fn foo {\n")
 6563     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6564     (write _test-input-stream "  var x/ebx: (addr t) <- length arr\n")
 6565     (write _test-input-stream "}\n")
 6566     # convert
 6567     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6568     (flush _test-output-buffered-file)
 6569 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 6575     # check output
 6576     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types/0")
 6577     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types/1")
 6578     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types/2")
 6579     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-user-defined-types/3")
 6580     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types/4")
 6581     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types/5")
 6582     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-user-defined-types/6")
 6583     (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")
 6584     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ebx"  "F - test-convert-length-of-array-of-user-defined-types/8")
 6585     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types/9")
 6586     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types/10")
 6587     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types/11")
 6588     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-user-defined-types/12")
 6589     (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")
 6590     (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")
 6591     (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")
 6592     (check-next-stream-line-equal _test-output-stream "    89/<- %ebx 0/r32/eax"  "F - test-convert-length-of-array-of-user-defined-types/16")
 6593     (check-next-stream-line-equal _test-output-stream "    5a/pop-to-edx"       "F - test-convert-length-of-array-of-user-defined-types/17")
 6594     (check-next-stream-line-equal _test-output-stream "    59/pop-to-ecx"       "F - test-convert-length-of-array-of-user-defined-types/18")
 6595     (check-next-stream-line-equal _test-output-stream "    58/pop-to-eax"       "F - test-convert-length-of-array-of-user-defined-types/19")
 6596     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ebx"  "F - test-convert-length-of-array-of-user-defined-types/20")
 6597     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-user-defined-types/21")
 6598     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types/22")
 6599     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types/23")
 6600     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types/24")
 6601     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-user-defined-types/25")
 6602     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-user-defined-types/26")
 6603     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types/27")
 6604     # . epilogue
 6605     89/<- %esp 5/r32/ebp
 6606     5d/pop-to-ebp
 6607     c3/return
 6608 
 6609 #######################################################
 6610 # Parsing
 6611 #######################################################
 6612 
 6613 == data
 6614 
 6615 # Global state added to each var record when parsing a function
 6616 Next-block-index:  # (addr int)
 6617     1/imm32
 6618 
 6619 Curr-block-depth:  # (addr int)
 6620     1/imm32
 6621 
 6622 == code
 6623 
 6624 parse-mu:  # in: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
 6625     # pseudocode
 6626     #   var curr-function: (addr handle function) = Program->functions
 6627     #   var curr-signature: (addr handle function) = Program->signatures
 6628     #   var curr-type: (addr handle typeinfo) = Program->types
 6629     #   var line: (stream byte 512)
 6630     #   var word-slice: slice
 6631     #   while true                                  # line loop
 6632     #     clear-stream(line)
 6633     #     read-line-buffered(in, line)
 6634     #     if (line->write == 0) break               # end of file
 6635     #     word-slice = next-mu-token(line)
 6636     #     if slice-empty?(word-slice)               # end of line
 6637     #       continue
 6638     #     else if slice-starts-with?(word-slice, "#")  # comment
 6639     #       continue                                # end of line
 6640     #     else if slice-equal?(word-slice, "fn")
 6641     #       var new-function: (handle function) = allocate(function)
 6642     #       var vars: (stack live-var 256)
 6643     #       populate-mu-function-header(line, new-function, vars)
 6644     #       populate-mu-function-body(in, new-function, vars)
 6645     #       assert(vars->top == 0)
 6646     #       *curr-function = new-function
 6647     #       curr-function = &new-function->next
 6648     #     else if slice-equal?(word-slice, "sig")
 6649     #       var new-function: (handle function) = allocate(function)
 6650     #       populate-mu-function-signature(line, new-function)
 6651     #       *curr-signature = new-function
 6652     #       curr-signature = &new-function->next
 6653     #     else if slice-equal?(word-slice, "type")
 6654     #       word-slice = next-mu-token(line)
 6655     #       type-id = pos-or-insert-slice(Type-id, word-slice)
 6656     #       var new-type: (handle typeinfo) = find-or-create-typeinfo(type-id)
 6657     #       assert(next-word(line) == "{")
 6658     #       populate-mu-type(in, new-type)
 6659     #     else
 6660     #       abort()
 6661     #
 6662     # . prologue
 6663     55/push-ebp
 6664     89/<- %ebp 4/r32/esp
 6665     # var curr-signature: (addr handle function) at *(ebp-4)
 6666     68/push _Program-signatures/imm32
 6667     # . save registers
 6668     50/push-eax
 6669     51/push-ecx
 6670     52/push-edx
 6671     53/push-ebx
 6672     56/push-esi
 6673     57/push-edi
 6674     # var line/ecx: (stream byte 512)
 6675     81 5/subop/subtract %esp 0x200/imm32
 6676     68/push 0x200/imm32/size
 6677     68/push 0/imm32/read
 6678     68/push 0/imm32/write
 6679     89/<- %ecx 4/r32/esp
 6680     # var word-slice/edx: slice
 6681     68/push 0/imm32/end
 6682     68/push 0/imm32/start
 6683     89/<- %edx 4/r32/esp
 6684     # var curr-function/edi: (addr handle function)
 6685     bf/copy-to-edi _Program-functions/imm32
 6686     # var vars/ebx: (stack live-var 256)
 6687     81 5/subop/subtract %esp 0xc00/imm32
 6688     68/push 0xc00/imm32/size
 6689     68/push 0/imm32/top
 6690     89/<- %ebx 4/r32/esp
 6691     {
 6692 $parse-mu:line-loop:
 6693       (clear-stream %ecx)
 6694       (read-line-buffered *(ebp+8) %ecx)
 6695       # if (line->write == 0) break
 6696       81 7/subop/compare *ecx 0/imm32
 6697       0f 84/jump-if-= break/disp32
 6698 +--  6 lines: #?       # dump line ------------------------------------------------------------------------------------------------------------------------------------------------------
 6704       (next-mu-token %ecx %edx)
 6705       # if slice-empty?(word-slice) continue
 6706       (slice-empty? %edx)  # => eax
 6707       3d/compare-eax-and 0/imm32/false
 6708       0f 85/jump-if-!= loop/disp32
 6709       # if (*word-slice->start == "#") continue
 6710       # . eax = *word-slice->start
 6711       8b/-> *edx 0/r32/eax
 6712       8a/copy-byte *eax 0/r32/AL
 6713       81 4/subop/and %eax 0xff/imm32
 6714       # . if (eax == '#') continue
 6715       3d/compare-eax-and 0x23/imm32/hash
 6716       0f 84/jump-if-= loop/disp32
 6717       # if (slice-equal?(word-slice, "fn")) parse a function
 6718       {
 6719 $parse-mu:fn:
 6720         (slice-equal? %edx "fn")  # => eax
 6721         3d/compare-eax-and 0/imm32/false
 6722         0f 84/jump-if-= break/disp32
 6723         # var new-function/esi: (handle function)
 6724         68/push 0/imm32
 6725         68/push 0/imm32
 6726         89/<- %esi 4/r32/esp
 6727         # populate-mu-function(line, in, vars, new-function)
 6728         (allocate Heap *Function-size %esi)
 6729         # var new-function-addr/eax: (addr function)
 6730         (lookup *esi *(esi+4))  # => eax
 6731         # initialize vars
 6732         (clear-stack %ebx)
 6733         #
 6734         (populate-mu-function-header %ecx %eax %ebx *(ebp+0xc) *(ebp+0x10))
 6735         (populate-mu-function-body *(ebp+8) %eax %ebx *(ebp+0xc) *(ebp+0x10))
 6736         # *curr-function = new-function
 6737         8b/-> *esi 0/r32/eax
 6738         89/<- *edi 0/r32/eax
 6739         8b/-> *(esi+4) 0/r32/eax
 6740         89/<- *(edi+4) 0/r32/eax
 6741         # curr-function = &new-function->next
 6742         # . var tmp/eax: (addr function) = lookup(new-function)
 6743         (lookup *esi *(esi+4))  # => eax
 6744         # . curr-function = &tmp->next
 6745         8d/copy-address *(eax+0x20) 7/r32/edi  # Function-next
 6746         # reclaim new-function
 6747         81 0/subop/add %esp 8/imm32
 6748         #
 6749         e9/jump $parse-mu:line-loop/disp32
 6750       }
 6751       # if (slice-equal?(word-slice, "sig")) parse a function signature
 6752       # Function signatures are for providing types to SubX functions.
 6753       {
 6754 $parse-mu:sig:
 6755         (slice-equal? %edx "sig")  # => eax
 6756         3d/compare-eax-and 0/imm32/false
 6757         0f 84/jump-if-= break/disp32
 6758         # edi = curr-function
 6759         57/push-edi
 6760         8b/-> *(ebp-4) 7/r32/edi
 6761         # var new-function/esi: (handle function)
 6762         68/push 0/imm32
 6763         68/push 0/imm32
 6764         89/<- %esi 4/r32/esp
 6765         # populate-mu-function(line, in, vars, new-function)
 6766         (allocate Heap *Function-size %esi)
 6767         # var new-function-addr/eax: (addr function)
 6768         (lookup *esi *(esi+4))  # => eax
 6769         #
 6770         (populate-mu-function-signature %ecx %eax *(ebp+0xc) *(ebp+0x10))
 6771         # *curr-signature = new-function
 6772         8b/-> *esi 0/r32/eax
 6773         89/<- *edi 0/r32/eax
 6774         8b/-> *(esi+4) 0/r32/eax
 6775         89/<- *(edi+4) 0/r32/eax
 6776         # curr-signature = &new-function->next
 6777         # . var tmp/eax: (addr function) = lookup(new-function)
 6778         (lookup *esi *(esi+4))  # => eax
 6779         # . curr-function = &tmp->next
 6780         8d/copy-address *(eax+0x20) 7/r32/edi  # Function-next
 6781         # reclaim new-function
 6782         81 0/subop/add %esp 8/imm32
 6783         # save curr-function
 6784         89/<- *(ebp-4) 7/r32/edi
 6785         # restore edi
 6786         5f/pop-to-edi
 6787         #
 6788         e9/jump $parse-mu:line-loop/disp32
 6789       }
 6790       # if (slice-equal?(word-slice, "type")) parse a type (struct/record) definition
 6791       {
 6792 $parse-mu:type:
 6793         (slice-equal? %edx "type")  # => eax
 6794         3d/compare-eax-and 0/imm32
 6795         0f 84/jump-if-= break/disp32
 6796         (next-mu-token %ecx %edx)
 6797         # var type-id/eax: int
 6798         (pos-or-insert-slice Type-id %edx)  # => eax
 6799         # spill
 6800         51/push-ecx
 6801         # var new-type/ecx: (handle typeinfo)
 6802         68/push 0/imm32
 6803         68/push 0/imm32
 6804         89/<- %ecx 4/r32/esp
 6805         (find-or-create-typeinfo %eax %ecx)
 6806         #
 6807         (lookup *ecx *(ecx+4))  # => eax
 6808         # TODO: ensure that 'line' has nothing else but '{'
 6809 #? (dump-typeinfos "=== aaa\n")
 6810         (populate-mu-type *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))  # => eax
 6811 #? (dump-typeinfos "=== zzz\n")
 6812         # reclaim new-type
 6813         81 0/subop/add %esp 8/imm32
 6814         # restore
 6815         59/pop-to-ecx
 6816         e9/jump $parse-mu:line-loop/disp32
 6817       }
 6818       # otherwise abort
 6819       e9/jump $parse-mu:error1/disp32
 6820     } # end line loop
 6821 $parse-mu:end:
 6822     # . reclaim locals
 6823     81 0/subop/add %esp 0x20c/imm32  # line
 6824     81 0/subop/add %esp 0xc08/imm32  # vars
 6825     81 0/subop/add %esp 8/imm32
 6826     # . restore registers
 6827     5f/pop-to-edi
 6828     5e/pop-to-esi
 6829     5b/pop-to-ebx
 6830     5a/pop-to-edx
 6831     59/pop-to-ecx
 6832     58/pop-to-eax
 6833     # . reclaim local
 6834     81 0/subop/add %esp 4/imm32
 6835     # . epilogue
 6836     89/<- %esp 5/r32/ebp
 6837     5d/pop-to-ebp
 6838     c3/return
 6839 
 6840 $parse-mu:error1:
 6841     # error("unexpected top-level command: " word-slice "\n")
 6842     (write-buffered *(ebp+0xc) "unexpected top-level command: ")
 6843     (write-slice-buffered *(ebp+0xc) %edx)
 6844     (write-buffered *(ebp+0xc) "\n")
 6845     (flush *(ebp+0xc))
 6846     (stop *(ebp+0x10) 1)
 6847     # never gets here
 6848 
 6849 $parse-mu:error2:
 6850     # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n")
 6851     (write-int32-hex-buffered *(ebp+0xc) *ebx)
 6852     (write-buffered *(ebp+0xc) " vars not reclaimed after fn '")
 6853     (write-slice-buffered *(ebp+0xc) *eax)  # Function-name
 6854     (write-buffered *(ebp+0xc) "'\n")
 6855     (flush *(ebp+0xc))
 6856     (stop *(ebp+0x10) 1)
 6857     # never gets here
 6858 
 6859 # scenarios considered:
 6860 # ✗ fn foo  # no block
 6861 # ✓ fn foo {
 6862 # ✗ fn foo { {
 6863 # ✗ fn foo { }
 6864 # ✗ fn foo { } {
 6865 # ✗ fn foo x {
 6866 # ✗ fn foo x: {
 6867 # ✓ fn foo x: int {
 6868 # ✓ fn foo x: int {
 6869 # ✓ fn foo x: int -> y/eax: int {
 6870 # TODO:
 6871 #   disallow outputs of type `(... addr ...)`
 6872 #   disallow inputs of type `(... addr ... addr ...)`
 6873 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)
 6874     # pseudocode:
 6875     #   var word-slice: slice
 6876     #   next-mu-token(first-line, word-slice)
 6877     #   assert(word-slice not in '{' '}' '->')
 6878     #   out->name = slice-to-string(word-slice)
 6879     #   ## inouts
 6880     #   while true
 6881     #     word-slice = next-mu-token(first-line)
 6882     #     if (word-slice == '{') goto done
 6883     #     if (word-slice == '->') break
 6884     #     assert(word-slice != '}')
 6885     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 6886     #     assert(v->register == null)
 6887     #     # v->block-depth is implicitly 0
 6888     #     out->inouts = append(v, out->inouts)
 6889     #     push(vars, {v, false})
 6890     #   ## outputs
 6891     #   while true
 6892     #     word-slice = next-mu-token(first-line)
 6893     #     if (word-slice == '{') break
 6894     #     assert(word-slice not in '}' '->')
 6895     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 6896     #     assert(v->register != null)
 6897     #     out->outputs = append(v, out->outputs)
 6898     #   done:
 6899     #
 6900     # . prologue
 6901     55/push-ebp
 6902     89/<- %ebp 4/r32/esp
 6903     # . save registers
 6904     50/push-eax
 6905     51/push-ecx
 6906     52/push-edx
 6907     53/push-ebx
 6908     57/push-edi
 6909     # edi = out
 6910     8b/-> *(ebp+0xc) 7/r32/edi
 6911     # var word-slice/ecx: slice
 6912     68/push 0/imm32/end
 6913     68/push 0/imm32/start
 6914     89/<- %ecx 4/r32/esp
 6915     # var v/ebx: (handle var)
 6916     68/push 0/imm32
 6917     68/push 0/imm32
 6918     89/<- %ebx 4/r32/esp
 6919     # read function name
 6920     (next-mu-token *(ebp+8) %ecx)
 6921     # error checking
 6922     # if (word-slice == '{') abort
 6923     (slice-equal? %ecx "{")   # => eax
 6924     3d/compare-eax-and 0/imm32/false
 6925     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6926     # if (word-slice == '->') abort
 6927     (slice-equal? %ecx "->")   # => eax
 6928     3d/compare-eax-and 0/imm32/false
 6929     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6930     # if (word-slice == '}') abort
 6931     (slice-equal? %ecx "}")   # => eax
 6932     3d/compare-eax-and 0/imm32/false
 6933     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6934     # save function name
 6935     (slice-to-string Heap %ecx %edi)  # Function-name
 6936     # save function inouts
 6937     {
 6938 $populate-mu-function-header:check-for-inout:
 6939       (next-mu-token *(ebp+8) %ecx)
 6940       # if (word-slice == '{') goto done
 6941       (slice-equal? %ecx "{")   # => eax
 6942       3d/compare-eax-and 0/imm32/false
 6943       0f 85/jump-if-!= $populate-mu-function-header:done/disp32
 6944       # if (word-slice == '->') break
 6945       (slice-equal? %ecx "->")   # => eax
 6946       3d/compare-eax-and 0/imm32/false
 6947       0f 85/jump-if-!= break/disp32
 6948       # if (word-slice == '}') abort
 6949       (slice-equal? %ecx "}")   # => eax
 6950       3d/compare-eax-and 0/imm32/false
 6951       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6952       # v = parse-var-with-type(word-slice, first-line)
 6953       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x14) *(ebp+0x18))
 6954       # assert(v->register == null)
 6955       # . eax: (addr var) = lookup(v)
 6956       (lookup *ebx *(ebx+4))  # => eax
 6957       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 6958       0f 85/jump-if-!= $populate-mu-function-header:error2/disp32
 6959       # v->block-depth is implicitly 0
 6960       #
 6961       # out->inouts = append(v, out->inouts)
 6962       8d/copy-address *(edi+8) 0/r32/eax  # Function-inouts
 6963       (append-list Heap  *ebx *(ebx+4)  *(edi+8) *(edi+0xc)  %eax)  # Function-inouts, Function-inouts
 6964       # push(vars, {v, false})
 6965       (push *(ebp+0x10) *ebx)
 6966       (push *(ebp+0x10) *(ebx+4))
 6967       (push *(ebp+0x10) 0)  # false
 6968       #
 6969       e9/jump loop/disp32
 6970     }
 6971     # save function outputs
 6972     {
 6973 $populate-mu-function-header:check-for-out:
 6974       (next-mu-token *(ebp+8) %ecx)
 6975       # if (word-slice == '{') break
 6976       (slice-equal? %ecx "{")   # => eax
 6977       3d/compare-eax-and 0/imm32/false
 6978       0f 85/jump-if-!= break/disp32
 6979       # if (word-slice == '->') abort
 6980       (slice-equal? %ecx "->")   # => eax
 6981       3d/compare-eax-and 0/imm32/false
 6982       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6983       # if (word-slice == '}') abort
 6984       (slice-equal? %ecx "}")   # => eax
 6985       3d/compare-eax-and 0/imm32/false
 6986       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6987       # v = parse-var-with-type(word-slice, first-line)
 6988       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x14) *(ebp+0x18))
 6989       # assert(var->register != null)
 6990       # . eax: (addr var) = lookup(v)
 6991       (lookup *ebx *(ebx+4))  # => eax
 6992       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 6993       0f 84/jump-if-= $populate-mu-function-header:error3/disp32
 6994       # out->outputs = append(v, out->outputs)
 6995       8d/copy-address *(edi+0x10) 0/r32/eax  # Function-outputs
 6996       (append-list Heap  *ebx *(ebx+4)  *(edi+0x10) *(edi+0x14)  %eax)  # Function-outputs, Function-outputs
 6997       #
 6998       e9/jump loop/disp32
 6999     }
 7000 $populate-mu-function-header:done:
 7001     (check-no-tokens-left *(ebp+8))
 7002 $populate-mu-function-header:end:
 7003     # . reclaim locals
 7004     81 0/subop/add %esp 0x10/imm32
 7005     # . restore registers
 7006     5f/pop-to-edi
 7007     5b/pop-to-ebx
 7008     5a/pop-to-edx
 7009     59/pop-to-ecx
 7010     58/pop-to-eax
 7011     # . epilogue
 7012     89/<- %esp 5/r32/ebp
 7013     5d/pop-to-ebp
 7014     c3/return
 7015 
 7016 $populate-mu-function-header:error1:
 7017     # error("function header not in form 'fn <name> {'")
 7018     (write-buffered *(ebp+0x14) "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '")
 7019     (flush *(ebp+0x14))
 7020     (rewind-stream *(ebp+8))
 7021     (write-stream-data *(ebp+0x14) *(ebp+8))
 7022     (write-buffered *(ebp+0x14) "'\n")
 7023     (flush *(ebp+0x14))
 7024     (stop *(ebp+0x18) 1)
 7025     # never gets here
 7026 
 7027 $populate-mu-function-header:error2:
 7028     # error("fn " fn ": function inout '" var "' cannot be in a register")
 7029     (write-buffered *(ebp+0x14) "fn ")
 7030     50/push-eax
 7031     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 7032     (write-buffered *(ebp+0x14) %eax)
 7033     58/pop-to-eax
 7034     (write-buffered *(ebp+0x14) ": function inout '")
 7035     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 7036     (write-buffered *(ebp+0x10) %eax)
 7037     (write-buffered *(ebp+0x14) "' cannot be in a register")
 7038     (flush *(ebp+0x14))
 7039     (stop *(ebp+0x18) 1)
 7040     # never gets here
 7041 
 7042 $populate-mu-function-header:error3:
 7043     # error("fn " fn ": function output '" var "' must be in a register")
 7044     (write-buffered *(ebp+0x14) "fn ")
 7045     50/push-eax
 7046     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 7047     (write-buffered *(ebp+0x14) %eax)
 7048     58/pop-to-eax
 7049     (write-buffered *(ebp+0x14) ": function output '")
 7050     (lookup *ebx *(ebx+4))  # => eax
 7051     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 7052     (write-buffered *(ebp+0x14) %eax)
 7053     (write-buffered *(ebp+0x14) "' must be in a register, in instruction '")
 7054     (rewind-stream *(ebp+8))
 7055     (write-stream-data *(ebp+0x14) *(ebp+8))
 7056     (write-buffered *(ebp+0x14) "'\n")
 7057     (flush *(ebp+0x14))
 7058     (stop *(ebp+0x18) 1)
 7059     # never gets here
 7060 
 7061 # scenarios considered:
 7062 # ✓ fn foo
 7063 # ✗ fn foo {
 7064 # ✓ fn foo x
 7065 # ✓ fn foo x: int
 7066 # ✓ fn foo x: int -> y/eax: int
 7067 # TODO:
 7068 #   disallow outputs of type `(... addr ...)`
 7069 #   disallow inputs of type `(... addr ... addr ...)`
 7070 populate-mu-function-signature:  # first-line: (addr stream byte), out: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
 7071     # pseudocode:
 7072     #   var word-slice: slice
 7073     #   next-mu-token(first-line, word-slice)
 7074     #   assert(word-slice not in '{' '}' '->')
 7075     #   out->name = slice-to-string(word-slice)
 7076     #   ## inouts
 7077     #   while true
 7078     #     word-slice = next-mu-token(first-line)
 7079     #     if slice-empty?(word-slice) break
 7080     #     if (word-slice == '->') break
 7081     #     assert(word-slice not in '{' '}')
 7082     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 7083     #     assert(v->register == null)
 7084     #     # v->block-depth is implicitly 0
 7085     #     out->inouts = append(v, out->inouts)
 7086     #   ## outputs
 7087     #   while true
 7088     #     word-slice = next-mu-token(first-line)
 7089     #     if slice-empty?(word-slice) break
 7090     #     assert(word-slice not in '{' '}' '->')
 7091     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 7092     #     assert(v->register != null)
 7093     #     out->outputs = append(v, out->outputs)
 7094     #
 7095     # . prologue
 7096     55/push-ebp
 7097     89/<- %ebp 4/r32/esp
 7098     # . save registers
 7099     50/push-eax
 7100     51/push-ecx
 7101     52/push-edx
 7102     53/push-ebx
 7103     57/push-edi
 7104     # edi = out
 7105     8b/-> *(ebp+0xc) 7/r32/edi
 7106     # var word-slice/ecx: slice
 7107     68/push 0/imm32/end
 7108     68/push 0/imm32/start
 7109     89/<- %ecx 4/r32/esp
 7110     # var v/ebx: (handle var)
 7111     68/push 0/imm32
 7112     68/push 0/imm32
 7113     89/<- %ebx 4/r32/esp
 7114     # read function name
 7115     (next-mu-token *(ebp+8) %ecx)
 7116     # error checking
 7117     # if (word-slice == '{') abort
 7118     (slice-equal? %ecx "{")   # => eax
 7119     3d/compare-eax-and 0/imm32/false
 7120     0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7121     # if (word-slice == '->') abort
 7122     (slice-equal? %ecx "->")   # => eax
 7123     3d/compare-eax-and 0/imm32/false
 7124     0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7125     # if (word-slice == '}') abort
 7126     (slice-equal? %ecx "}")   # => eax
 7127     3d/compare-eax-and 0/imm32/false
 7128     0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7129     # save function name
 7130     (slice-to-string Heap %ecx %edi)  # Function-name
 7131     # save function inouts
 7132     {
 7133 $populate-mu-function-signature:check-for-inout:
 7134       (next-mu-token *(ebp+8) %ecx)
 7135       (slice-empty? %ecx)  # => eax
 7136       3d/compare-eax-and 0/imm32/false
 7137       0f 85/jump-if-!= break/disp32
 7138       # if (word-slice == '->') break
 7139       (slice-equal? %ecx "->")   # => eax
 7140       3d/compare-eax-and 0/imm32/false
 7141       0f 85/jump-if-!= break/disp32
 7142       # if (word-slice == '{') abort
 7143       (slice-equal? %ecx "{")   # => eax
 7144       3d/compare-eax-and 0/imm32/false
 7145       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7146       # if (word-slice == '}') abort
 7147       (slice-equal? %ecx "}")   # => eax
 7148       3d/compare-eax-and 0/imm32/false
 7149       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7150       # v = parse-var-with-type(word-slice, first-line)
 7151       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x10) *(ebp+0x14))
 7152       # assert(v->register == null)
 7153       # . eax: (addr var) = lookup(v)
 7154       (lookup *ebx *(ebx+4))  # => eax
 7155       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 7156       0f 85/jump-if-!= $populate-mu-function-signature:error2/disp32
 7157       # v->block-depth is implicitly 0
 7158       #
 7159       # out->inouts = append(v, out->inouts)
 7160       8d/copy-address *(edi+8) 0/r32/eax  # Function-inouts
 7161       (append-list Heap  *ebx *(ebx+4)  *(edi+8) *(edi+0xc)  %eax)  # Function-inouts, Function-inouts
 7162       #
 7163       e9/jump loop/disp32
 7164     }
 7165     # save function outputs
 7166     {
 7167 $populate-mu-function-signature:check-for-out:
 7168       (next-mu-token *(ebp+8) %ecx)
 7169       (slice-empty? %ecx)  # => eax
 7170       3d/compare-eax-and 0/imm32/false
 7171       0f 85/jump-if-!= break/disp32
 7172       # if (word-slice == '{') abort
 7173       (slice-equal? %ecx "{")   # => eax
 7174       3d/compare-eax-and 0/imm32/false
 7175       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7176       # if (word-slice == '->') abort
 7177       (slice-equal? %ecx "->")   # => eax
 7178       3d/compare-eax-and 0/imm32/false
 7179       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7180       # if (word-slice == '}') abort
 7181       (slice-equal? %ecx "}")   # => eax
 7182       3d/compare-eax-and 0/imm32/false
 7183       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7184       # v = parse-var-with-type(word-slice, first-line)
 7185       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x10) *(ebp+0x14))
 7186       # assert(var->register != null)
 7187       # . eax: (addr var) = lookup(v)
 7188       (lookup *ebx *(ebx+4))  # => eax
 7189       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 7190       0f 84/jump-if-= $populate-mu-function-signature:error3/disp32
 7191       # out->outputs = append(v, out->outputs)
 7192       8d/copy-address *(edi+0x10) 0/r32/eax  # Function-outputs
 7193       (append-list Heap  *ebx *(ebx+4)  *(edi+0x10) *(edi+0x14)  %eax)  # Function-outputs, Function-outputs
 7194       #
 7195       e9/jump loop/disp32
 7196     }
 7197 $populate-mu-function-signature:done:
 7198     (check-no-tokens-left *(ebp+8))
 7199 $populate-mu-function-signature:end:
 7200     # . reclaim locals
 7201     81 0/subop/add %esp 0x10/imm32
 7202     # . restore registers
 7203     5f/pop-to-edi
 7204     5b/pop-to-ebx
 7205     5a/pop-to-edx
 7206     59/pop-to-ecx
 7207     58/pop-to-eax
 7208     # . epilogue
 7209     89/<- %esp 5/r32/ebp
 7210     5d/pop-to-ebp
 7211     c3/return
 7212 
 7213 $populate-mu-function-signature:error1:
 7214     # error("function signature not in form 'fn <name> {'")
 7215     (write-buffered *(ebp+0x10) "function signature not in form 'fn <name> [inouts] [-> outputs] {' -- '")
 7216     (flush *(ebp+0x10))
 7217     (rewind-stream *(ebp+8))
 7218     (write-stream-data *(ebp+0x10) *(ebp+8))
 7219     (write-buffered *(ebp+0x10) "'\n")
 7220     (flush *(ebp+0x10))
 7221     (stop *(ebp+0x14) 1)
 7222     # never gets here
 7223 
 7224 $populate-mu-function-signature:error2:
 7225     # error("fn " fn ": function inout '" var "' cannot be in a register")
 7226     (write-buffered *(ebp+0x10) "fn ")
 7227     50/push-eax
 7228     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 7229     (write-buffered *(ebp+0x10) %eax)
 7230     58/pop-to-eax
 7231     (write-buffered *(ebp+0x10) ": function inout '")
 7232     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 7233     (write-buffered *(ebp+0x10) %eax)
 7234     (write-buffered *(ebp+0x10) "' cannot be in a register")
 7235     (flush *(ebp+0x10))
 7236     (stop *(ebp+0x14) 1)
 7237     # never gets here
 7238 
 7239 $populate-mu-function-signature:error3:
 7240     # error("fn " fn ": function output '" var "' must be in a register")
 7241     (write-buffered *(ebp+0x10) "fn ")
 7242     50/push-eax
 7243     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 7244     (write-buffered *(ebp+0x10) %eax)
 7245     58/pop-to-eax
 7246     (write-buffered *(ebp+0x10) ": function output '")
 7247     (lookup *ebx *(ebx+4))  # => eax
 7248     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 7249     (write-buffered *(ebp+0x10) %eax)
 7250     (write-buffered *(ebp+0x10) "' must be in a register, in instruction '")
 7251     (rewind-stream *(ebp+8))
 7252     (write-stream-data *(ebp+0x10) *(ebp+8))
 7253     (write-buffered *(ebp+0x10) "'\n")
 7254     (flush *(ebp+0x10))
 7255     (stop *(ebp+0x14) 1)
 7256     # never gets here
 7257 
 7258 test-function-header-with-arg:
 7259     # . prologue
 7260     55/push-ebp
 7261     89/<- %ebp 4/r32/esp
 7262     # setup
 7263     (clear-stream _test-input-stream)
 7264     (write _test-input-stream "foo n: int {\n")
 7265     # var result/ecx: function
 7266     2b/subtract *Function-size 4/r32/esp
 7267     89/<- %ecx 4/r32/esp
 7268     (zero-out %ecx *Function-size)
 7269     # var vars/ebx: (stack live-var 16)
 7270     81 5/subop/subtract %esp 0xc0/imm32
 7271     68/push 0xc0/imm32/size
 7272     68/push 0/imm32/top
 7273     89/<- %ebx 4/r32/esp
 7274     # convert
 7275     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 7276     # check result->name
 7277     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 7278     (check-strings-equal %eax "foo" "F - test-function-header-with-arg/name")
 7279     # var v/edx: (addr var) = result->inouts->value
 7280     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 7281     (lookup *eax *(eax+4))  # List-value List-value => eax
 7282     89/<- %edx 0/r32/eax
 7283     # check v->name
 7284     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 7285     (check-strings-equal %eax "n" "F - test-function-header-with-arg/inout:0")
 7286     # check v->type
 7287     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 7288     (check-ints-equal *eax 1 "F - test-function-header-with-arg/inout:0/type:0")  # Type-tree-is-atom
 7289     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-arg/inout:0/type:1")  # Type-tree-value
 7290     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-arg/inout:0/type:2")  # Type-tree-right
 7291     # . epilogue
 7292     89/<- %esp 5/r32/ebp
 7293     5d/pop-to-ebp
 7294     c3/return
 7295 
 7296 test-function-header-with-multiple-args:
 7297     # . prologue
 7298     55/push-ebp
 7299     89/<- %ebp 4/r32/esp
 7300     # setup
 7301     (clear-stream _test-input-stream)
 7302     (write _test-input-stream "foo a: int, b: int c: int {\n")
 7303     # result/ecx: function
 7304     2b/subtract *Function-size 4/r32/esp
 7305     89/<- %ecx 4/r32/esp
 7306     (zero-out %ecx *Function-size)
 7307     # var vars/ebx: (stack live-var 16)
 7308     81 5/subop/subtract %esp 0xc0/imm32
 7309     68/push 0xc0/imm32/size
 7310     68/push 0/imm32/top
 7311     89/<- %ebx 4/r32/esp
 7312     # convert
 7313     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 7314     # check result->name
 7315     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 7316     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args/name")
 7317     # var inouts/edx: (addr list var) = lookup(result->inouts)
 7318     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 7319     89/<- %edx 0/r32/eax
 7320 $test-function-header-with-multiple-args:inout0:
 7321     # var v/ebx: (addr var) = lookup(inouts->value)
 7322     (lookup *edx *(edx+4))  # List-value List-value => eax
 7323     89/<- %ebx 0/r32/eax
 7324     # check v->name
 7325     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7326     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args/inout:0")  # Var-name
 7327     # check v->type
 7328     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7329     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:0/type:0")  # Type-tree-is-atom
 7330     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:0/type:1")  # Type-tree-value
 7331     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:0/type:2")  # Type-tree-right
 7332 $test-function-header-with-multiple-args:inout1:
 7333     # inouts = lookup(inouts->next)
 7334     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 7335     89/<- %edx 0/r32/eax
 7336     # v = lookup(inouts->value)
 7337     (lookup *edx *(edx+4))  # List-value List-value => eax
 7338     89/<- %ebx 0/r32/eax
 7339     # check v->name
 7340     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7341     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args/inout:1")  # Var-name
 7342     # check v->type
 7343     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7344     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:1/type:0")  # Type-tree-is-atom
 7345     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:1/type:1")  # Type-tree-value
 7346     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:1/type:2")  # Type-tree-right
 7347 $test-function-header-with-multiple-args:inout2:
 7348     # inouts = lookup(inouts->next)
 7349     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 7350     89/<- %edx 0/r32/eax
 7351     # v = lookup(inouts->value)
 7352     (lookup *edx *(edx+4))  # List-value List-value => eax
 7353     89/<- %ebx 0/r32/eax
 7354     # check v->name
 7355     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7356     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args/inout:2")  # Var-name
 7357     # check v->type
 7358     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7359     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:2/type:0")  # Type-tree-is-atom
 7360     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:2/type:1")  # Type-tree-value
 7361     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:2/type:2")  # Type-tree-right
 7362     # . epilogue
 7363     89/<- %esp 5/r32/ebp
 7364     5d/pop-to-ebp
 7365     c3/return
 7366 
 7367 test-function-header-with-multiple-args-and-outputs:
 7368     # . prologue
 7369     55/push-ebp
 7370     89/<- %ebp 4/r32/esp
 7371     # setup
 7372     (clear-stream _test-input-stream)
 7373     (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx: int {\n")
 7374     # result/ecx: function
 7375     2b/subtract *Function-size 4/r32/esp
 7376     89/<- %ecx 4/r32/esp
 7377     (zero-out %ecx *Function-size)
 7378     # var vars/ebx: (stack live-var 16)
 7379     81 5/subop/subtract %esp 0xc0/imm32
 7380     68/push 0xc0/imm32/size
 7381     68/push 0/imm32/top
 7382     89/<- %ebx 4/r32/esp
 7383     # convert
 7384     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 7385     # check result->name
 7386     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 7387     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args-and-outputs/name")
 7388     # var inouts/edx: (addr list var) = lookup(result->inouts)
 7389     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 7390     89/<- %edx 0/r32/eax
 7391 $test-function-header-with-multiple-args-and-outputs:inout0:
 7392     # var v/ebx: (addr var) = lookup(inouts->value)
 7393     (lookup *edx *(edx+4))  # List-value List-value => eax
 7394     89/<- %ebx 0/r32/eax
 7395     # check v->name
 7396     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7397     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args-and-outputs/inout:0")
 7398     # check v->type
 7399     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7400     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:0")  # Type-tree-is-atom
 7401     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1")  # Type-tree-value
 7402     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:2")  # Type-tree-right
 7403 $test-function-header-with-multiple-args-and-outputs:inout1:
 7404     # inouts = lookup(inouts->next)
 7405     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 7406     89/<- %edx 0/r32/eax
 7407     # v = lookup(inouts->value)
 7408     (lookup *edx *(edx+4))  # List-value List-value => eax
 7409     89/<- %ebx 0/r32/eax
 7410     # check v->name
 7411     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7412     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args-and-outputs/inout:1")
 7413     # check v->type
 7414     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7415     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:0")  # Type-tree-is-atom
 7416     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1")  # Type-tree-value
 7417     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:2")  # Type-tree-right
 7418 $test-function-header-with-multiple-args-and-outputs:inout2:
 7419     # inouts = lookup(inouts->next)
 7420     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 7421     89/<- %edx 0/r32/eax
 7422     # v = lookup(inouts->value)
 7423     (lookup *edx *(edx+4))  # List-value List-value => eax
 7424     89/<- %ebx 0/r32/eax
 7425     # check v->name
 7426     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7427     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args-and-outputs/inout:2")
 7428     # check v->type
 7429     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7430     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:0")  # Type-tree-is-atom
 7431     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1")  # Type-tree-value
 7432     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:2")  # Type-tree-right
 7433 $test-function-header-with-multiple-args-and-outputs:out0:
 7434     # var outputs/edx: (addr list var) = lookup(result->outputs)
 7435     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
 7436     89/<- %edx 0/r32/eax
 7437     # v = lookup(outputs->value)
 7438     (lookup *edx *(edx+4))  # List-value List-value => eax
 7439     89/<- %ebx 0/r32/eax
 7440     # check v->name
 7441     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7442     (check-strings-equal %eax "x" "F - test-function-header-with-multiple-args-and-outputs/output:0")
 7443     # check v->register
 7444     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 7445     (check-strings-equal %eax "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register")
 7446     # check v->type
 7447     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7448     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:0")  # Type-tree-is-atom
 7449     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1")  # Type-tree-value
 7450     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:2")  # Type-tree-right
 7451 $test-function-header-with-multiple-args-and-outputs:out1:
 7452     # outputs = lookup(outputs->next)
 7453     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 7454     89/<- %edx 0/r32/eax
 7455     # v = lookup(inouts->value)
 7456     (lookup *edx *(edx+4))  # List-value List-value => eax
 7457     89/<- %ebx 0/r32/eax
 7458     # check v->name
 7459     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 7460     (check-strings-equal %eax "y" "F - test-function-header-with-multiple-args-and-outputs/output:1")
 7461     # check v->register
 7462     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 7463     (check-strings-equal %eax "edx" "F - test-function-header-with-multiple-args-and-outputs/output:1/register")
 7464     # check v->type
 7465     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 7466     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:0")  # Type-tree-is-atom
 7467     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1")  # Type-tree-value
 7468     (check-ints-equal *(eax+0c) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:2")  # Type-tree-right
 7469     # . epilogue
 7470     89/<- %esp 5/r32/ebp
 7471     5d/pop-to-ebp
 7472     c3/return
 7473 
 7474 # format for variables with types
 7475 #   x: int
 7476 #   x: int,
 7477 #   x/eax: int
 7478 #   x/eax: int,
 7479 # ignores at most one trailing comma
 7480 # WARNING: modifies name
 7481 parse-var-with-type:  # name: (addr slice), first-line: (addr stream byte), out: (addr handle var), err: (addr buffered-file), ed: (addr exit-descriptor)
 7482     # pseudocode:
 7483     #   var s: slice
 7484     #   if (!slice-ends-with(name, ":"))
 7485     #     abort
 7486     #   --name->end to skip ':'
 7487     #   next-token-from-slice(name->start, name->end, '/', s)
 7488     #   new-var-from-slice(s, out)
 7489     #   ## register
 7490     #   next-token-from-slice(s->end, name->end, '/', s)
 7491     #   if (!slice-empty?(s))
 7492     #     out->register = slice-to-string(s)
 7493     #   ## type
 7494     #   var type: (handle type-tree) = parse-type(first-line)
 7495     #   out->type = type
 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     53/push-ebx
 7505     56/push-esi
 7506     57/push-edi
 7507     # esi = name
 7508     8b/-> *(ebp+8) 6/r32/esi
 7509     # if (!slice-ends-with?(name, ":")) abort
 7510     8b/-> *(esi+4) 1/r32/ecx  # Slice-end
 7511     49/decrement-ecx
 7512     8a/copy-byte *ecx 1/r32/CL
 7513     81 4/subop/and %ecx 0xff/imm32
 7514     81 7/subop/compare %ecx 0x3a/imm32/colon
 7515     0f 85/jump-if-!= $parse-var-with-type:abort/disp32
 7516     # --name->end to skip ':'
 7517     ff 1/subop/decrement *(esi+4)
 7518     # var s/ecx: slice
 7519     68/push 0/imm32/end
 7520     68/push 0/imm32/start
 7521     89/<- %ecx 4/r32/esp
 7522 $parse-var-with-type:parse-name:
 7523     (next-token-from-slice *esi *(esi+4) 0x2f %ecx)  # Slice-start, Slice-end, '/'
 7524 $parse-var-with-type:create-var:
 7525     # new-var-from-slice(s, out)
 7526     (new-var-from-slice Heap %ecx *(ebp+0x10))
 7527     # save out->register
 7528 $parse-var-with-type:save-register:
 7529     # . var out-addr/edi: (addr var) = lookup(*out)
 7530     8b/-> *(ebp+0x10) 7/r32/edi
 7531     (lookup *edi *(edi+4))  # => eax
 7532     89/<- %edi 0/r32/eax
 7533     # . s = next-token(...)
 7534     (next-token-from-slice *(ecx+4) *(esi+4) 0x2f %ecx)  # s->end, name->end, '/'
 7535     # . if (!slice-empty?(s)) out->register = slice-to-string(s)
 7536     {
 7537 $parse-var-with-type:write-register:
 7538       (slice-empty? %ecx)  # => eax
 7539       3d/compare-eax-and 0/imm32/false
 7540       75/jump-if-!= break/disp8
 7541       # out->register = slice-to-string(s)
 7542       8d/copy-address *(edi+0x18) 0/r32/eax  # Var-register
 7543       (slice-to-string Heap %ecx %eax)
 7544     }
 7545 $parse-var-with-type:save-type:
 7546     8d/copy-address *(edi+8) 0/r32/eax  # Var-type
 7547     (parse-type Heap *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 7548 $parse-var-with-type:end:
 7549     # . reclaim locals
 7550     81 0/subop/add %esp 8/imm32
 7551     # . restore registers
 7552     5f/pop-to-edi
 7553     5e/pop-to-esi
 7554     5b/pop-to-ebx
 7555     5a/pop-to-edx
 7556     59/pop-to-ecx
 7557     58/pop-to-eax
 7558     # . epilogue
 7559     89/<- %esp 5/r32/ebp
 7560     5d/pop-to-ebp
 7561     c3/return
 7562 
 7563 $parse-var-with-type:abort:
 7564     # error("var should have form 'name: type' in '" line "'\n")
 7565     (write-buffered *(ebp+0x14) "var should have form 'name: type' in '")
 7566     (flush *(ebp+0x14))
 7567     (rewind-stream *(ebp+0xc))
 7568     (write-stream-data *(ebp+0x14) *(ebp+0xc))
 7569     (write-buffered *(ebp+0x14) "'\n")
 7570     (flush *(ebp+0x14))
 7571     (stop *(ebp+0x18) 1)
 7572     # never gets here
 7573 
 7574 parse-type:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle type-tree), err: (addr buffered-file), ed: (addr exit-descriptor)
 7575     # pseudocode:
 7576     #   var s: slice = next-mu-token(in)
 7577     #   assert s != ""
 7578     #   assert s != "->"
 7579     #   assert s != "{"
 7580     #   assert s != "}"
 7581     #   if s == ")"
 7582     #     return
 7583     #   out = allocate(Type-tree)
 7584     #   if s != "("
 7585     #     HACK: if s is an int, parse and return it
 7586     #     out->is-atom? = true
 7587     #     if (s[0] == "_")
 7588     #       out->value = type-parameter
 7589     #       out->parameter-name = slice-to-string(ad, s)
 7590     #     else
 7591     #       out->value = pos-or-insert-slice(Type-id, s)
 7592     #     return
 7593     #   out->left = parse-type(ad, in)
 7594     #   out->right = parse-type-tree(ad, in)
 7595     #
 7596     # . prologue
 7597     55/push-ebp
 7598     89/<- %ebp 4/r32/esp
 7599     # . save registers
 7600     50/push-eax
 7601     51/push-ecx
 7602     52/push-edx
 7603     # clear out
 7604     (zero-out *(ebp+0x10) *Handle-size)
 7605     # var s/ecx: slice
 7606     68/push 0/imm32
 7607     68/push 0/imm32
 7608     89/<- %ecx 4/r32/esp
 7609     # s = next-mu-token(in)
 7610     (next-mu-token *(ebp+0xc) %ecx)
 7611 #?     (write-buffered Stderr "tok: ")
 7612 #?     (write-slice-buffered Stderr %ecx)
 7613 #?     (write-buffered Stderr "$\n")
 7614 #?     (flush Stderr)
 7615     # assert s != ""
 7616     (slice-equal? %ecx "")  # => eax
 7617     3d/compare-eax-and 0/imm32/false
 7618     0f 85/jump-if-!= $parse-type:abort/disp32
 7619     # assert s != "{"
 7620     (slice-equal? %ecx "{")  # => eax
 7621     3d/compare-eax-and 0/imm32/false
 7622     0f 85/jump-if-!= $parse-type:abort/disp32
 7623     # assert s != "}"
 7624     (slice-equal? %ecx "}")  # => eax
 7625     3d/compare-eax-and 0/imm32/false
 7626     0f 85/jump-if-!= $parse-type:abort/disp32
 7627     # assert s != "->"
 7628     (slice-equal? %ecx "->")  # => eax
 7629     3d/compare-eax-and 0/imm32/false
 7630     0f 85/jump-if-!= $parse-type:abort/disp32
 7631     # if (s == ")") return
 7632     (slice-equal? %ecx ")")  # => eax
 7633     3d/compare-eax-and 0/imm32/false
 7634     0f 85/jump-if-!= $parse-type:end/disp32
 7635     # out = new tree
 7636     (allocate *(ebp+8) *Type-tree-size *(ebp+0x10))
 7637     # var out-addr/edx: (addr type-tree) = lookup(*out)
 7638     8b/-> *(ebp+0x10) 2/r32/edx
 7639     (lookup *edx *(edx+4))  # => eax
 7640     89/<- %edx 0/r32/eax
 7641     {
 7642       # if (s != "(") break
 7643       (slice-equal? %ecx "(")  # => eax
 7644       3d/compare-eax-and 0/imm32/false
 7645       0f 85/jump-if-!= break/disp32
 7646       # if s is a number, store it in the type's size field
 7647       {
 7648 $parse-type:check-for-int:
 7649         # var tmp/eax: byte = *s->slice
 7650         8b/-> *ecx 0/r32/eax
 7651         8a/copy-byte *eax 0/r32/AL
 7652         81 4/subop/and %eax 0xff/imm32
 7653         # TODO: raise an error on `var x: (array int a)`
 7654         (is-decimal-digit? %eax)  # => eax
 7655         3d/compare-eax-and 0/imm32/false
 7656         74/jump-if-= break/disp8
 7657         #
 7658         (is-hex-int? %ecx)  # => eax
 7659         3d/compare-eax-and 0/imm32/false
 7660         74/jump-if-= break/disp8
 7661 $parse-type:int:
 7662         (check-mu-hex-int %ecx *(ebp+0x14) *(ebp+0x18))
 7663         (parse-hex-int-from-slice %ecx)  # => eax
 7664         c7 0/subop/copy *(edx+4) 9/imm32/type-id-array-capacity  # Type-tree-value
 7665         89/<- *(edx+8) 0/r32/eax  # Type-tree-value-size
 7666         e9/jump $parse-type:end/disp32
 7667       }
 7668 $parse-type:atom:
 7669       # out->is-atom? = true
 7670       c7 0/subop/copy *edx 1/imm32/true  # Type-tree-is-atom
 7671       {
 7672 $parse-type:check-for-type-parameter:
 7673         # var tmp/eax: byte = *s->slice
 7674         8b/-> *ecx 0/r32/eax
 7675         8a/copy-byte *eax 0/r32/AL
 7676         81 4/subop/and %eax 0xff/imm32
 7677         # if (tmp != '_') break
 7678         3d/compare-eax-and 0x5f/imm32/_
 7679         75/jump-if-!= break/disp8
 7680 $parse-type:type-parameter:
 7681         # out->value = type-parameter
 7682         c7 0/subop/copy *(edx+4) 0xa/imm32/type-parameter  # Type-tree-value
 7683         # out->parameter-name = slice-to-string(ad, s)
 7684         8d/copy-address *(edx+8) 0/r32/eax  # Type-tree-parameter-name
 7685         (slice-to-string *(ebp+8) %ecx %eax)
 7686         e9/jump $parse-type:end/disp32
 7687       }
 7688 $parse-type:non-type-parameter:
 7689       # out->value = pos-or-insert-slice(Type-id, s)
 7690       (pos-or-insert-slice Type-id %ecx)  # => eax
 7691       89/<- *(edx+4) 0/r32/eax  # Type-tree-value
 7692       e9/jump $parse-type:end/disp32
 7693     }
 7694 $parse-type:non-atom:
 7695     # otherwise s == "("
 7696     # out->left = parse-type(ad, in)
 7697     8d/copy-address *(edx+4) 0/r32/eax  # Type-tree-left
 7698     (parse-type *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 7699     # out->right = parse-type-tree(ad, in)
 7700     8d/copy-address *(edx+0xc) 0/r32/eax  # Type-tree-right
 7701     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 7702 $parse-type:end:
 7703     # . reclaim locals
 7704     81 0/subop/add %esp 8/imm32
 7705     # . restore registers
 7706     5a/pop-to-edx
 7707     59/pop-to-ecx
 7708     58/pop-to-eax
 7709     # . epilogue
 7710     89/<- %esp 5/r32/ebp
 7711     5d/pop-to-ebp
 7712     c3/return
 7713 
 7714 $parse-type:abort:
 7715     # error("unexpected token when parsing type: '" s "'\n")
 7716     (write-buffered *(ebp+0x14) "unexpected token when parsing type: '")
 7717     (write-slice-buffered *(ebp+0x14) %ecx)
 7718     (write-buffered *(ebp+0x14) "'\n")
 7719     (flush *(ebp+0x14))
 7720     (stop *(ebp+0x18) 1)
 7721     # never gets here
 7722 
 7723 parse-type-tree:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle type-tree), err: (addr buffered-file), ed: (addr exit-descriptor)
 7724     # pseudocode:
 7725     #   var tmp: (handle type-tree) = parse-type(ad, in)
 7726     #   if tmp == 0
 7727     #     return 0
 7728     #   out = allocate(Type-tree)
 7729     #   out->left = tmp
 7730     #   out->right = parse-type-tree(ad, in)
 7731     #
 7732     # . prologue
 7733     55/push-ebp
 7734     89/<- %ebp 4/r32/esp
 7735     # . save registers
 7736     50/push-eax
 7737     51/push-ecx
 7738     52/push-edx
 7739     #
 7740     (zero-out *(ebp+0x10) *Handle-size)
 7741     # var tmp/ecx: (handle type-tree)
 7742     68/push 0/imm32
 7743     68/push 0/imm32
 7744     89/<- %ecx 4/r32/esp
 7745     # tmp = parse-type(ad, in)
 7746     (parse-type *(ebp+8) *(ebp+0xc) %ecx *(ebp+0x14) *(ebp+0x18))
 7747     # if (tmp == 0) return
 7748     81 7/subop/compare *ecx 0/imm32
 7749     74/jump-if-= $parse-type-tree:end/disp8
 7750     # out = new tree
 7751     (allocate *(ebp+8) *Type-tree-size *(ebp+0x10))
 7752     # var out-addr/edx: (addr tree) = lookup(*out)
 7753     8b/-> *(ebp+0x10) 2/r32/edx
 7754     (lookup *edx *(edx+4))  # => eax
 7755     89/<- %edx 0/r32/eax
 7756     # out->left = tmp
 7757     8b/-> *ecx 0/r32/eax
 7758     89/<- *(edx+4) 0/r32/eax  # Type-tree-left
 7759     8b/-> *(ecx+4) 0/r32/eax
 7760     89/<- *(edx+8) 0/r32/eax  # Type-tree-left
 7761     # out->right = parse-type-tree(ad, in)
 7762     8d/copy-address *(edx+0xc) 0/r32/eax  # Type-tree-right
 7763     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 7764 $parse-type-tree:end:
 7765     # . reclaim locals
 7766     81 0/subop/add %esp 8/imm32
 7767     # . restore registers
 7768     5a/pop-to-edx
 7769     59/pop-to-ecx
 7770     58/pop-to-eax
 7771     # . epilogue
 7772     89/<- %esp 5/r32/ebp
 7773     5d/pop-to-ebp
 7774     c3/return
 7775 
 7776 next-mu-token:  # in: (addr stream byte), out: (addr slice)
 7777     # pseudocode:
 7778     # start:
 7779     #   skip-chars-matching-whitespace(in)
 7780     #   if in->read >= in->write              # end of in
 7781     #     out = {0, 0}
 7782     #     return
 7783     #   out->start = &in->data[in->read]
 7784     #   var curr-byte/eax: byte = in->data[in->read]
 7785     #   if curr->byte == ','                  # comment token
 7786     #     ++in->read
 7787     #     goto start
 7788     #   if curr-byte == '#'                   # comment
 7789     #     goto done                             # treat as eof
 7790     #   if curr-byte == '"'                   # string literal
 7791     #     skip-string(in)
 7792     #     goto done                           # no metadata
 7793     #   if curr-byte == '('
 7794     #     ++in->read
 7795     #     goto done
 7796     #   if curr-byte == ')'
 7797     #     ++in->read
 7798     #     goto done
 7799     #   # read a word
 7800     #   while true
 7801     #     if in->read >= in->write
 7802     #       break
 7803     #     curr-byte = in->data[in->read]
 7804     #     if curr-byte == ' '
 7805     #       break
 7806     #     if curr-byte == '\r'
 7807     #       break
 7808     #     if curr-byte == '\n'
 7809     #       break
 7810     #     if curr-byte == '('
 7811     #       break
 7812     #     if curr-byte == ')'
 7813     #       break
 7814     #     if curr-byte == ','
 7815     #       break
 7816     #     ++in->read
 7817     # done:
 7818     #   out->end = &in->data[in->read]
 7819     #
 7820     # . prologue
 7821     55/push-ebp
 7822     89/<- %ebp 4/r32/esp
 7823     # . save registers
 7824     50/push-eax
 7825     51/push-ecx
 7826     56/push-esi
 7827     57/push-edi
 7828     # esi = in
 7829     8b/-> *(ebp+8) 6/r32/esi
 7830     # edi = out
 7831     8b/-> *(ebp+0xc) 7/r32/edi
 7832 $next-mu-token:start:
 7833     (skip-chars-matching-whitespace %esi)
 7834 $next-mu-token:check0:
 7835     # if (in->read >= in->write) return out = {0, 0}
 7836     # . ecx = in->read
 7837     8b/-> *(esi+4) 1/r32/ecx
 7838     # . if (ecx >= in->write) return out = {0, 0}
 7839     3b/compare<- *esi 1/r32/ecx
 7840     c7 0/subop/copy *edi 0/imm32
 7841     c7 0/subop/copy *(edi+4) 0/imm32
 7842     0f 8d/jump-if->= $next-mu-token:end/disp32
 7843     # out->start = &in->data[in->read]
 7844     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
 7845     89/<- *edi 0/r32/eax
 7846     # var curr-byte/eax: byte = in->data[in->read]
 7847     31/xor-with %eax 0/r32/eax
 7848     8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
 7849     {
 7850 $next-mu-token:check-for-comma:
 7851       # if (curr-byte != ',') break
 7852       3d/compare-eax-and 0x2c/imm32/comma
 7853       75/jump-if-!= break/disp8
 7854       # ++in->read
 7855       ff 0/subop/increment *(esi+4)
 7856       # restart
 7857       e9/jump $next-mu-token:start/disp32
 7858     }
 7859     {
 7860 $next-mu-token:check-for-comment:
 7861       # if (curr-byte != '#') break
 7862       3d/compare-eax-and 0x23/imm32/pound
 7863       75/jump-if-!= break/disp8
 7864       # return eof
 7865       e9/jump $next-mu-token:done/disp32
 7866     }
 7867     {
 7868 $next-mu-token:check-for-string-literal:
 7869       # if (curr-byte != '"') break
 7870       3d/compare-eax-and 0x22/imm32/dquote
 7871       75/jump-if-!= break/disp8
 7872       (skip-string %esi)
 7873       # return
 7874       e9/jump $next-mu-token:done/disp32
 7875     }
 7876     {
 7877 $next-mu-token:check-for-open-paren:
 7878       # if (curr-byte != '(') break
 7879       3d/compare-eax-and 0x28/imm32/open-paren
 7880       75/jump-if-!= break/disp8
 7881       # ++in->read
 7882       ff 0/subop/increment *(esi+4)
 7883       # return
 7884       e9/jump $next-mu-token:done/disp32
 7885     }
 7886     {
 7887 $next-mu-token:check-for-close-paren:
 7888       # if (curr-byte != ')') break
 7889       3d/compare-eax-and 0x29/imm32/close-paren
 7890       75/jump-if-!= break/disp8
 7891       # ++in->read
 7892       ff 0/subop/increment *(esi+4)
 7893       # return
 7894       e9/jump $next-mu-token:done/disp32
 7895     }
 7896     {
 7897 $next-mu-token:regular-word-without-metadata:
 7898       # if (in->read >= in->write) break
 7899       # . ecx = in->read
 7900       8b/-> *(esi+4) 1/r32/ecx
 7901       # . if (ecx >= in->write) break
 7902       3b/compare<- *esi 1/r32/ecx
 7903       7d/jump-if->= break/disp8
 7904       # var c/eax: byte = in->data[in->read]
 7905       31/xor-with %eax 0/r32/eax
 7906       8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
 7907       # if (c == ' ') break
 7908       3d/compare-eax-and 0x20/imm32/space
 7909       74/jump-if-= break/disp8
 7910       # if (c == '\r') break
 7911       3d/compare-eax-and 0xd/imm32/carriage-return
 7912       74/jump-if-= break/disp8
 7913       # if (c == '\n') break
 7914       3d/compare-eax-and 0xa/imm32/newline
 7915       74/jump-if-= break/disp8
 7916       # if (c == '(') break
 7917       3d/compare-eax-and 0x28/imm32/open-paren
 7918       0f 84/jump-if-= break/disp32
 7919       # if (c == ')') break
 7920       3d/compare-eax-and 0x29/imm32/close-paren
 7921       0f 84/jump-if-= break/disp32
 7922       # if (c == ',') break
 7923       3d/compare-eax-and 0x2c/imm32/comma
 7924       0f 84/jump-if-= break/disp32
 7925       # ++in->read
 7926       ff 0/subop/increment *(esi+4)
 7927       #
 7928       e9/jump loop/disp32
 7929     }
 7930 $next-mu-token:done:
 7931     # out->end = &in->data[in->read]
 7932     8b/-> *(esi+4) 1/r32/ecx
 7933     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
 7934     89/<- *(edi+4) 0/r32/eax
 7935 $next-mu-token:end:
 7936     # . restore registers
 7937     5f/pop-to-edi
 7938     5e/pop-to-esi
 7939     59/pop-to-ecx
 7940     58/pop-to-eax
 7941     # . epilogue
 7942     89/<- %esp 5/r32/ebp
 7943     5d/pop-to-ebp
 7944     c3/return
 7945 
 7946 pos-or-insert-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
 7947     # . prologue
 7948     55/push-ebp
 7949     89/<- %ebp 4/r32/esp
 7950     # if (pos-slice(arr, s) != -1) return it
 7951     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
 7952     3d/compare-eax-and -1/imm32
 7953     75/jump-if-!= $pos-or-insert-slice:end/disp8
 7954 $pos-or-insert-slice:insert:
 7955     # var s2/eax: (handle array byte)
 7956     68/push 0/imm32
 7957     68/push 0/imm32
 7958     89/<- %eax 4/r32/esp
 7959     (slice-to-string Heap *(ebp+0xc) %eax)
 7960     # throw away alloc-id
 7961     (lookup *eax *(eax+4))  # => eax
 7962     (write-int *(ebp+8) %eax)
 7963     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
 7964 $pos-or-insert-slice:end:
 7965     # . reclaim locals
 7966     81 0/subop/add %esp 8/imm32
 7967     # . epilogue
 7968     89/<- %esp 5/r32/ebp
 7969     5d/pop-to-ebp
 7970     c3/return
 7971 
 7972 # return the index in an array of strings matching 's', -1 if not found
 7973 # index is denominated in elements, not bytes
 7974 pos-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
 7975     # . prologue
 7976     55/push-ebp
 7977     89/<- %ebp 4/r32/esp
 7978     # . save registers
 7979     51/push-ecx
 7980     52/push-edx
 7981     53/push-ebx
 7982     56/push-esi
 7983 #?     (write-buffered Stderr "pos-slice: ")
 7984 #?     (write-slice-buffered Stderr *(ebp+0xc))
 7985 #?     (write-buffered Stderr "\n")
 7986 #?     (flush Stderr)
 7987     # esi = arr
 7988     8b/-> *(ebp+8) 6/r32/esi
 7989     # var index/ecx: int = 0
 7990     b9/copy-to-ecx 0/imm32
 7991     # var curr/edx: (addr (addr array byte)) = arr->data
 7992     8d/copy-address *(esi+0xc) 2/r32/edx
 7993     # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write]
 7994     8b/-> *esi 3/r32/ebx
 7995     8d/copy-address *(esi+ebx+0xc) 3/r32/ebx
 7996     {
 7997 #?       (write-buffered Stderr "  ")
 7998 #?       (write-int32-hex-buffered Stderr %ecx)
 7999 #?       (write-buffered Stderr "\n")
 8000 #?       (flush Stderr)
 8001       # if (curr >= max) return -1
 8002       39/compare %edx 3/r32/ebx
 8003       b8/copy-to-eax -1/imm32
 8004       73/jump-if-addr>= $pos-slice:end/disp8
 8005       # if (slice-equal?(s, *curr)) break
 8006       (slice-equal? *(ebp+0xc) *edx)  # => eax
 8007       3d/compare-eax-and 0/imm32/false
 8008       75/jump-if-!= break/disp8
 8009       # ++index
 8010       41/increment-ecx
 8011       # curr += 4
 8012       81 0/subop/add %edx 4/imm32
 8013       #
 8014       eb/jump loop/disp8
 8015     }
 8016     # return index
 8017     89/<- %eax 1/r32/ecx
 8018 $pos-slice:end:
 8019 #?     (write-buffered Stderr "=> ")
 8020 #?     (write-int32-hex-buffered Stderr %eax)
 8021 #?     (write-buffered Stderr "\n")
 8022     # . restore registers
 8023     5e/pop-to-esi
 8024     5b/pop-to-ebx
 8025     5a/pop-to-edx
 8026     59/pop-to-ecx
 8027     # . epilogue
 8028     89/<- %esp 5/r32/ebp
 8029     5d/pop-to-ebp
 8030     c3/return
 8031 
 8032 test-parse-var-with-type:
 8033     # . prologue
 8034     55/push-ebp
 8035     89/<- %ebp 4/r32/esp
 8036     # (eax..ecx) = "x:"
 8037     b8/copy-to-eax "x:"/imm32
 8038     8b/-> *eax 1/r32/ecx
 8039     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8040     05/add-to-eax 4/imm32
 8041     # var slice/ecx: slice = {eax, ecx}
 8042     51/push-ecx
 8043     50/push-eax
 8044     89/<- %ecx 4/r32/esp
 8045     # _test-input-stream contains "int"
 8046     (clear-stream _test-input-stream)
 8047     (write _test-input-stream "int")
 8048     # var v/edx: (handle var)
 8049     68/push 0/imm32
 8050     68/push 0/imm32
 8051     89/<- %edx 4/r32/esp
 8052     #
 8053     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 8054     # var v-addr/edx: (addr var) = lookup(v)
 8055     (lookup *edx *(edx+4))  # => eax
 8056     89/<- %edx 0/r32/eax
 8057     # check v-addr->name
 8058     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 8059     (check-strings-equal %eax "x" "F - test-parse-var-with-type/name")
 8060     # check v-addr->type
 8061     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 8062     (check-ints-equal *eax 1 "F - test-parse-var-with-type/type:0")  # Type-tree-is-atom
 8063     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type/type:1")  # Type-tree-value
 8064     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type/type:2")  # Type-tree-right
 8065     # . epilogue
 8066     89/<- %esp 5/r32/ebp
 8067     5d/pop-to-ebp
 8068     c3/return
 8069 
 8070 test-parse-var-with-type-and-register:
 8071     # . prologue
 8072     55/push-ebp
 8073     89/<- %ebp 4/r32/esp
 8074     # (eax..ecx) = "x/eax:"
 8075     b8/copy-to-eax "x/eax:"/imm32
 8076     8b/-> *eax 1/r32/ecx
 8077     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8078     05/add-to-eax 4/imm32
 8079     # var slice/ecx: slice = {eax, ecx}
 8080     51/push-ecx
 8081     50/push-eax
 8082     89/<- %ecx 4/r32/esp
 8083     # _test-input-stream contains "int"
 8084     (clear-stream _test-input-stream)
 8085     (write _test-input-stream "int")
 8086     # var v/edx: (handle var)
 8087     68/push 0/imm32
 8088     68/push 0/imm32
 8089     89/<- %edx 4/r32/esp
 8090     #
 8091     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 8092     # var v-addr/edx: (addr var) = lookup(v)
 8093     (lookup *edx *(edx+4))  # => eax
 8094     89/<- %edx 0/r32/eax
 8095     # check v-addr->name
 8096     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 8097     (check-strings-equal %eax "x" "F - test-parse-var-with-type-and-register/name")
 8098     # check v-addr->register
 8099     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 8100     (check-strings-equal %eax "eax" "F - test-parse-var-with-type-and-register/register")
 8101     # check v-addr->type
 8102     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 8103     (check-ints-equal *eax 1 "F - test-parse-var-with-type-and-register/type:0")  # Type-tree-is-atom
 8104     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type-and-register/type:1")  # Type-tree-left
 8105     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type-and-register/type:2")  # Type-tree-right
 8106     # . epilogue
 8107     89/<- %esp 5/r32/ebp
 8108     5d/pop-to-ebp
 8109     c3/return
 8110 
 8111 test-parse-var-with-trailing-characters:
 8112     # . prologue
 8113     55/push-ebp
 8114     89/<- %ebp 4/r32/esp
 8115     # (eax..ecx) = "x:"
 8116     b8/copy-to-eax "x:"/imm32
 8117     8b/-> *eax 1/r32/ecx
 8118     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8119     05/add-to-eax 4/imm32
 8120     # var slice/ecx: slice = {eax, ecx}
 8121     51/push-ecx
 8122     50/push-eax
 8123     89/<- %ecx 4/r32/esp
 8124     # _test-input-stream contains "int,"
 8125     (clear-stream _test-input-stream)
 8126     (write _test-input-stream "int,")
 8127     # var v/edx: (handle var)
 8128     68/push 0/imm32
 8129     68/push 0/imm32
 8130     89/<- %edx 4/r32/esp
 8131     #
 8132     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 8133     # var v-addr/edx: (addr var) = lookup(v)
 8134     (lookup *edx *(edx+4))  # => eax
 8135     89/<- %edx 0/r32/eax
 8136     # check v-addr->name
 8137     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 8138     (check-strings-equal %eax "x" "F - test-parse-var-with-trailing-characters/name")
 8139     # check v-addr->register
 8140     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-trailing-characters/register")  # Var-register
 8141     # check v-addr->type
 8142     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 8143     (check-ints-equal *eax 1 "F - test-parse-var-with-trailing-characters/type:0")  # Type-tree-is-atom
 8144     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-trailing-characters/type:1")  # Type-tree-left
 8145     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-trailing-characters/type:1")  # Type-tree-right
 8146     # . epilogue
 8147     89/<- %esp 5/r32/ebp
 8148     5d/pop-to-ebp
 8149     c3/return
 8150 
 8151 test-parse-var-with-register-and-trailing-characters:
 8152     # . prologue
 8153     55/push-ebp
 8154     89/<- %ebp 4/r32/esp
 8155     # (eax..ecx) = "x/eax:"
 8156     b8/copy-to-eax "x/eax:"/imm32
 8157     8b/-> *eax 1/r32/ecx
 8158     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8159     05/add-to-eax 4/imm32
 8160     # var slice/ecx: slice = {eax, ecx}
 8161     51/push-ecx
 8162     50/push-eax
 8163     89/<- %ecx 4/r32/esp
 8164     # _test-input-stream contains "int,"
 8165     (clear-stream _test-input-stream)
 8166     (write _test-input-stream "int,")
 8167     # var v/edx: (handle var)
 8168     68/push 0/imm32
 8169     68/push 0/imm32
 8170     89/<- %edx 4/r32/esp
 8171     #
 8172     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 8173     # var v-addr/edx: (addr var) = lookup(v)
 8174     (lookup *edx *(edx+4))  # => eax
 8175     89/<- %edx 0/r32/eax
 8176     # check v-addr->name
 8177     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 8178     (check-strings-equal %eax "x" "F - test-parse-var-with-register-and-trailing-characters/name")
 8179     # check v-addr->register
 8180     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 8181     (check-strings-equal %eax "eax" "F - test-parse-var-with-register-and-trailing-characters/register")
 8182     # check v-addr->type
 8183     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 8184     (check-ints-equal *eax 1 "F - test-parse-var-with-register-and-trailing-characters/type:0")  # Type-tree-is-atom
 8185     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-register-and-trailing-characters/type:1")  # Type-tree-left
 8186     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-register-and-trailing-characters/type:2")  # Type-tree-right
 8187     # . epilogue
 8188     89/<- %esp 5/r32/ebp
 8189     5d/pop-to-ebp
 8190     c3/return
 8191 
 8192 test-parse-var-with-compound-type:
 8193     # . prologue
 8194     55/push-ebp
 8195     89/<- %ebp 4/r32/esp
 8196     # (eax..ecx) = "x:"
 8197     b8/copy-to-eax "x:"/imm32
 8198     8b/-> *eax 1/r32/ecx
 8199     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8200     05/add-to-eax 4/imm32
 8201     # var slice/ecx: slice = {eax, ecx}
 8202     51/push-ecx
 8203     50/push-eax
 8204     89/<- %ecx 4/r32/esp
 8205     # _test-input-stream contains "(addr int)"
 8206     (clear-stream _test-input-stream)
 8207     (write _test-input-stream "(addr int)")
 8208     # var v/edx: (handle var)
 8209     68/push 0/imm32
 8210     68/push 0/imm32
 8211     89/<- %edx 4/r32/esp
 8212     #
 8213     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 8214     # var v-addr/edx: (addr var) = lookup(v)
 8215     (lookup *edx *(edx+4))  # => eax
 8216     89/<- %edx 0/r32/eax
 8217     # check v-addr->name
 8218     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 8219     (check-strings-equal %eax "x" "F - test-parse-var-with-compound-type/name")
 8220     # check v-addr->register
 8221     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-compound-type/register")  # Var-register
 8222     # - check v-addr->type
 8223     # var type/edx: (addr type-tree) = var->type
 8224     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 8225     89/<- %edx 0/r32/eax
 8226     # type is a non-atom
 8227     (check-ints-equal *edx 0 "F - test-parse-var-with-compound-type/type:0")  # Type-tree-is-atom
 8228     # type->left == atom(addr)
 8229     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
 8230     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:1")  # Type-tree-is-atom
 8231     (check-ints-equal *(eax+4) 2 "F - test-parse-var-with-compound-type/type:2")  # Type-tree-value
 8232     # type->right->left == atom(int)
 8233     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
 8234     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
 8235     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:3")  # Type-tree-is-atom
 8236     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-compound-type/type:4")  # Type-tree-value
 8237     # type->right->right == null
 8238     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-compound-type/type:5")  # Type-tree-right
 8239     # . epilogue
 8240     89/<- %esp 5/r32/ebp
 8241     5d/pop-to-ebp
 8242     c3/return
 8243 
 8244 # identifier starts with a letter or '$' or '_'
 8245 # no constraints at the moment on later letters
 8246 # all we really want to do so far is exclude '{', '}' and '->'
 8247 is-identifier?:  # in: (addr slice) -> result/eax: boolean
 8248     # . prologue
 8249     55/push-ebp
 8250     89/<- %ebp 4/r32/esp
 8251     # if (slice-empty?(in)) return false
 8252     (slice-empty? *(ebp+8))  # => eax
 8253     3d/compare-eax-and 0/imm32/false
 8254     75/jump-if-!= $is-identifier?:false/disp8
 8255     # var c/eax: byte = *in->start
 8256     8b/-> *(ebp+8) 0/r32/eax
 8257     8b/-> *eax 0/r32/eax
 8258     8a/copy-byte *eax 0/r32/AL
 8259     81 4/subop/and %eax 0xff/imm32
 8260     # if (c == '$') return true
 8261     3d/compare-eax-and 0x24/imm32/$
 8262     74/jump-if-= $is-identifier?:true/disp8
 8263     # if (c == '_') return true
 8264     3d/compare-eax-and 0x5f/imm32/_
 8265     74/jump-if-= $is-identifier?:true/disp8
 8266     # drop case
 8267     25/and-eax-with 0x5f/imm32
 8268     # if (c < 'A') return false
 8269     3d/compare-eax-and 0x41/imm32/A
 8270     7c/jump-if-< $is-identifier?:false/disp8
 8271     # if (c > 'Z') return false
 8272     3d/compare-eax-and 0x5a/imm32/Z
 8273     7f/jump-if-> $is-identifier?:false/disp8
 8274     # otherwise return true
 8275 $is-identifier?:true:
 8276     b8/copy-to-eax 1/imm32/true
 8277     eb/jump $is-identifier?:end/disp8
 8278 $is-identifier?:false:
 8279     b8/copy-to-eax 0/imm32/false
 8280 $is-identifier?:end:
 8281     # . epilogue
 8282     89/<- %esp 5/r32/ebp
 8283     5d/pop-to-ebp
 8284     c3/return
 8285 
 8286 test-is-identifier-dollar:
 8287     # . prologue
 8288     55/push-ebp
 8289     89/<- %ebp 4/r32/esp
 8290     # (eax..ecx) = "$a"
 8291     b8/copy-to-eax "$a"/imm32
 8292     8b/-> *eax 1/r32/ecx
 8293     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8294     05/add-to-eax 4/imm32
 8295     # var slice/ecx: slice = {eax, ecx}
 8296     51/push-ecx
 8297     50/push-eax
 8298     89/<- %ecx 4/r32/esp
 8299     #
 8300     (is-identifier? %ecx)
 8301     (check-ints-equal %eax 1 "F - test-is-identifier-dollar")
 8302     # . epilogue
 8303     89/<- %esp 5/r32/ebp
 8304     5d/pop-to-ebp
 8305     c3/return
 8306 
 8307 test-is-identifier-underscore:
 8308     # . prologue
 8309     55/push-ebp
 8310     89/<- %ebp 4/r32/esp
 8311     # (eax..ecx) = "_a"
 8312     b8/copy-to-eax "_a"/imm32
 8313     8b/-> *eax 1/r32/ecx
 8314     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8315     05/add-to-eax 4/imm32
 8316     # var slice/ecx: slice = {eax, ecx}
 8317     51/push-ecx
 8318     50/push-eax
 8319     89/<- %ecx 4/r32/esp
 8320     #
 8321     (is-identifier? %ecx)
 8322     (check-ints-equal %eax 1 "F - test-is-identifier-underscore")
 8323     # . epilogue
 8324     89/<- %esp 5/r32/ebp
 8325     5d/pop-to-ebp
 8326     c3/return
 8327 
 8328 test-is-identifier-a:
 8329     # . prologue
 8330     55/push-ebp
 8331     89/<- %ebp 4/r32/esp
 8332     # (eax..ecx) = "a$"
 8333     b8/copy-to-eax "a$"/imm32
 8334     8b/-> *eax 1/r32/ecx
 8335     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8336     05/add-to-eax 4/imm32
 8337     # var slice/ecx: slice = {eax, ecx}
 8338     51/push-ecx
 8339     50/push-eax
 8340     89/<- %ecx 4/r32/esp
 8341     #
 8342     (is-identifier? %ecx)
 8343     (check-ints-equal %eax 1 "F - test-is-identifier-a")
 8344     # . epilogue
 8345     89/<- %esp 5/r32/ebp
 8346     5d/pop-to-ebp
 8347     c3/return
 8348 
 8349 test-is-identifier-z:
 8350     # . prologue
 8351     55/push-ebp
 8352     89/<- %ebp 4/r32/esp
 8353     # (eax..ecx) = "z$"
 8354     b8/copy-to-eax "z$"/imm32
 8355     8b/-> *eax 1/r32/ecx
 8356     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8357     05/add-to-eax 4/imm32
 8358     # var slice/ecx: slice = {eax, ecx}
 8359     51/push-ecx
 8360     50/push-eax
 8361     89/<- %ecx 4/r32/esp
 8362     #
 8363     (is-identifier? %ecx)
 8364     (check-ints-equal %eax 1 "F - test-is-identifier-z")
 8365     # . epilogue
 8366     89/<- %esp 5/r32/ebp
 8367     5d/pop-to-ebp
 8368     c3/return
 8369 
 8370 test-is-identifier-A:
 8371     # . prologue
 8372     55/push-ebp
 8373     89/<- %ebp 4/r32/esp
 8374     # (eax..ecx) = "A$"
 8375     b8/copy-to-eax "A$"/imm32
 8376     8b/-> *eax 1/r32/ecx
 8377     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8378     05/add-to-eax 4/imm32
 8379     # var slice/ecx: slice = {eax, ecx}
 8380     51/push-ecx
 8381     50/push-eax
 8382     89/<- %ecx 4/r32/esp
 8383     #
 8384     (is-identifier? %ecx)
 8385     (check-ints-equal %eax 1 "F - test-is-identifier-A")
 8386     # . epilogue
 8387     89/<- %esp 5/r32/ebp
 8388     5d/pop-to-ebp
 8389     c3/return
 8390 
 8391 test-is-identifier-Z:
 8392     # . prologue
 8393     55/push-ebp
 8394     89/<- %ebp 4/r32/esp
 8395     # (eax..ecx) = "Z$"
 8396     b8/copy-to-eax "Z$"/imm32
 8397     8b/-> *eax 1/r32/ecx
 8398     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8399     05/add-to-eax 4/imm32
 8400     # var slice/ecx: slice = {eax, ecx}
 8401     51/push-ecx
 8402     50/push-eax
 8403     89/<- %ecx 4/r32/esp
 8404     #
 8405     (is-identifier? %ecx)
 8406     (check-ints-equal %eax 1 "F - test-is-identifier-Z")
 8407     # . epilogue
 8408     89/<- %esp 5/r32/ebp
 8409     5d/pop-to-ebp
 8410     c3/return
 8411 
 8412 test-is-identifier-at:
 8413     # character before 'A' is invalid
 8414     # . prologue
 8415     55/push-ebp
 8416     89/<- %ebp 4/r32/esp
 8417     # (eax..ecx) = "@a"
 8418     b8/copy-to-eax "@a"/imm32
 8419     8b/-> *eax 1/r32/ecx
 8420     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8421     05/add-to-eax 4/imm32
 8422     # var slice/ecx: slice = {eax, ecx}
 8423     51/push-ecx
 8424     50/push-eax
 8425     89/<- %ecx 4/r32/esp
 8426     #
 8427     (is-identifier? %ecx)
 8428     (check-ints-equal %eax 0 "F - test-is-identifier-@")
 8429     # . epilogue
 8430     89/<- %esp 5/r32/ebp
 8431     5d/pop-to-ebp
 8432     c3/return
 8433 
 8434 test-is-identifier-square-bracket:
 8435     # character after 'Z' is invalid
 8436     # . prologue
 8437     55/push-ebp
 8438     89/<- %ebp 4/r32/esp
 8439     # (eax..ecx) = "[a"
 8440     b8/copy-to-eax "[a"/imm32
 8441     8b/-> *eax 1/r32/ecx
 8442     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8443     05/add-to-eax 4/imm32
 8444     # var slice/ecx: slice = {eax, ecx}
 8445     51/push-ecx
 8446     50/push-eax
 8447     89/<- %ecx 4/r32/esp
 8448     #
 8449     (is-identifier? %ecx)
 8450     (check-ints-equal %eax 0 "F - test-is-identifier-@")
 8451     # . epilogue
 8452     89/<- %esp 5/r32/ebp
 8453     5d/pop-to-ebp
 8454     c3/return
 8455 
 8456 test-is-identifier-backtick:
 8457     # character before 'a' is invalid
 8458     # . prologue
 8459     55/push-ebp
 8460     89/<- %ebp 4/r32/esp
 8461     # (eax..ecx) = "`a"
 8462     b8/copy-to-eax "`a"/imm32
 8463     8b/-> *eax 1/r32/ecx
 8464     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8465     05/add-to-eax 4/imm32
 8466     # var slice/ecx: slice = {eax, ecx}
 8467     51/push-ecx
 8468     50/push-eax
 8469     89/<- %ecx 4/r32/esp
 8470     #
 8471     (is-identifier? %ecx)
 8472     (check-ints-equal %eax 0 "F - test-is-identifier-backtick")
 8473     # . epilogue
 8474     89/<- %esp 5/r32/ebp
 8475     5d/pop-to-ebp
 8476     c3/return
 8477 
 8478 test-is-identifier-curly-brace-open:
 8479     # character after 'z' is invalid; also used for blocks
 8480     # . prologue
 8481     55/push-ebp
 8482     89/<- %ebp 4/r32/esp
 8483     # (eax..ecx) = "{a"
 8484     b8/copy-to-eax "{a"/imm32
 8485     8b/-> *eax 1/r32/ecx
 8486     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8487     05/add-to-eax 4/imm32
 8488     # var slice/ecx: slice = {eax, ecx}
 8489     51/push-ecx
 8490     50/push-eax
 8491     89/<- %ecx 4/r32/esp
 8492     #
 8493     (is-identifier? %ecx)
 8494     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open")
 8495     # . epilogue
 8496     89/<- %esp 5/r32/ebp
 8497     5d/pop-to-ebp
 8498     c3/return
 8499 
 8500 test-is-identifier-curly-brace-close:
 8501     # . prologue
 8502     55/push-ebp
 8503     89/<- %ebp 4/r32/esp
 8504     # (eax..ecx) = "}a"
 8505     b8/copy-to-eax "}a"/imm32
 8506     8b/-> *eax 1/r32/ecx
 8507     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8508     05/add-to-eax 4/imm32
 8509     # var slice/ecx: slice = {eax, ecx}
 8510     51/push-ecx
 8511     50/push-eax
 8512     89/<- %ecx 4/r32/esp
 8513     #
 8514     (is-identifier? %ecx)
 8515     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close")
 8516     # . epilogue
 8517     89/<- %esp 5/r32/ebp
 8518     5d/pop-to-ebp
 8519     c3/return
 8520 
 8521 test-is-identifier-hyphen:
 8522     # disallow leading '-' since '->' has special meaning
 8523     # . prologue
 8524     55/push-ebp
 8525     89/<- %ebp 4/r32/esp
 8526     # (eax..ecx) = "-a"
 8527     b8/copy-to-eax "-a"/imm32
 8528     8b/-> *eax 1/r32/ecx
 8529     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8530     05/add-to-eax 4/imm32
 8531     # var slice/ecx: slice = {eax, ecx}
 8532     51/push-ecx
 8533     50/push-eax
 8534     89/<- %ecx 4/r32/esp
 8535     #
 8536     (is-identifier? %ecx)
 8537     (check-ints-equal %eax 0 "F - test-is-identifier-hyphen")
 8538     # . epilogue
 8539     89/<- %esp 5/r32/ebp
 8540     5d/pop-to-ebp
 8541     c3/return
 8542 
 8543 populate-mu-function-body:  # in: (addr buffered-file), out: (addr function), vars: (addr stack live-var), err: (addr buffered-file), ed: (addr exit-descriptor)
 8544     # . prologue
 8545     55/push-ebp
 8546     89/<- %ebp 4/r32/esp
 8547     # . save registers
 8548     50/push-eax
 8549     56/push-esi
 8550     57/push-edi
 8551     # esi = in
 8552     8b/-> *(ebp+8) 6/r32/esi
 8553     # edi = out
 8554     8b/-> *(ebp+0xc) 7/r32/edi
 8555     # initialize some global state
 8556     c7 0/subop/copy *Curr-block-depth 1/imm32
 8557     # parse-mu-block(in, vars, out, out->body)
 8558     8d/copy-address *(edi+0x18) 0/r32/eax  # Function-body
 8559     (parse-mu-block %esi *(ebp+0x10) %edi %eax *(ebp+0x14) *(ebp+0x18))
 8560 $populate-mu-function-body:end:
 8561     # . restore registers
 8562     5f/pop-to-edi
 8563     5e/pop-to-esi
 8564     58/pop-to-eax
 8565     # . epilogue
 8566     89/<- %esp 5/r32/ebp
 8567     5d/pop-to-ebp
 8568     c3/return
 8569 
 8570 # parses a block, assuming that the leading '{' has already been read by the caller
 8571 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)
 8572     # pseudocode:
 8573     #   var line: (stream byte 512)
 8574     #   var word-slice: slice
 8575     #   allocate(Heap, Stmt-size, out)
 8576     #   var out-addr: (addr block) = lookup(*out)
 8577     #   out-addr->tag = 0/block
 8578     #   out-addr->var = some unique name
 8579     #   push(vars, {out-addr->var, false})
 8580     #   while true                                  # line loop
 8581     #     clear-stream(line)
 8582     #     read-line-buffered(in, line)
 8583     #     if (line->write == 0) break               # end of file
 8584     #     word-slice = next-mu-token(line)
 8585     #     if slice-empty?(word-slice)               # end of line
 8586     #       continue
 8587     #     else if slice-starts-with?(word-slice, "#")
 8588     #       continue
 8589     #     else if slice-equal?(word-slice, "{")
 8590     #       assert(no-tokens-in(line))
 8591     #       block = parse-mu-block(in, vars, fn)
 8592     #       append-to-block(out-addr, block)
 8593     #     else if slice-equal?(word-slice, "}")
 8594     #       break
 8595     #     else if slice-ends-with?(word-slice, ":")
 8596     #       # TODO: error-check the rest of 'line'
 8597     #       --word-slice->end to skip ':'
 8598     #       named-block = parse-mu-named-block(word-slice, in, vars, fn)
 8599     #       append-to-block(out-addr, named-block)
 8600     #     else if slice-equal?(word-slice, "var")
 8601     #       var-def = parse-mu-var-def(line, vars, fn)
 8602     #       append-to-block(out-addr, var-def)
 8603     #     else
 8604     #       stmt = parse-mu-stmt(line, vars, fn)
 8605     #       append-to-block(out-addr, stmt)
 8606     #   pop(vars)
 8607     #
 8608     # . prologue
 8609     55/push-ebp
 8610     89/<- %ebp 4/r32/esp
 8611     # . save registers
 8612     50/push-eax
 8613     51/push-ecx
 8614     52/push-edx
 8615     53/push-ebx
 8616     57/push-edi
 8617     # var line/ecx: (stream byte 512)
 8618     81 5/subop/subtract %esp 0x200/imm32
 8619     68/push 0x200/imm32/size
 8620     68/push 0/imm32/read
 8621     68/push 0/imm32/write
 8622     89/<- %ecx 4/r32/esp
 8623     # var word-slice/edx: slice
 8624     68/push 0/imm32/end
 8625     68/push 0/imm32/start
 8626     89/<- %edx 4/r32/esp
 8627     # allocate into out
 8628     (allocate Heap *Stmt-size *(ebp+0x14))
 8629     # var out-addr/edi: (addr block) = lookup(*out)
 8630     8b/-> *(ebp+0x14) 7/r32/edi
 8631     (lookup *edi *(edi+4))  # => eax
 8632     89/<- %edi 0/r32/eax
 8633     # out-addr->tag is 0 (block) by default
 8634     # set out-addr->var
 8635     8d/copy-address *(edi+0xc) 0/r32/eax  # Block-var
 8636     (new-block-name *(ebp+0x10) %eax)
 8637     # push(vars, out-addr->var)
 8638     (push *(ebp+0xc) *(edi+0xc))  # Block-var
 8639     (push *(ebp+0xc) *(edi+0x10))  # Block-var
 8640     (push *(ebp+0xc) 0)  # false
 8641     # increment *Curr-block-depth
 8642     ff 0/subop/increment *Curr-block-depth
 8643     {
 8644 $parse-mu-block:line-loop:
 8645       # line = read-line-buffered(in)
 8646       (clear-stream %ecx)
 8647       (read-line-buffered *(ebp+8) %ecx)
 8648 #?       (write-buffered Stderr "line: ")
 8649 #?       (write-stream-data Stderr %ecx)
 8650 #? #?       (write-buffered Stderr Newline)  # line has its own newline
 8651 #?       (flush Stderr)
 8652 #?       (rewind-stream %ecx)
 8653       # if (line->write == 0) break
 8654       81 7/subop/compare *ecx 0/imm32
 8655       0f 84/jump-if-= break/disp32
 8656 #?       (write-buffered Stderr "vars:\n")
 8657 #?       (dump-vars *(ebp+0xc))
 8658       # word-slice = next-mu-token(line)
 8659       (next-mu-token %ecx %edx)
 8660 #?       (write-buffered Stderr "word: ")
 8661 #?       (write-slice-buffered Stderr %edx)
 8662 #?       (write-buffered Stderr Newline)
 8663 #?       (flush Stderr)
 8664       # if slice-empty?(word-slice) continue
 8665       (slice-empty? %edx)
 8666       3d/compare-eax-and 0/imm32/false
 8667       0f 85/jump-if-!= loop/disp32
 8668       # if (slice-starts-with?(word-slice, '#') continue
 8669       # . eax = *word-slice->start
 8670       8b/-> *edx 0/r32/eax
 8671       8a/copy-byte *eax 0/r32/AL
 8672       81 4/subop/and %eax 0xff/imm32
 8673       # . if (eax == '#') continue
 8674       3d/compare-eax-and 0x23/imm32/hash
 8675       0f 84/jump-if-= loop/disp32
 8676       # if slice-equal?(word-slice, "{")
 8677       {
 8678 $parse-mu-block:check-for-block:
 8679         (slice-equal? %edx "{")
 8680         3d/compare-eax-and 0/imm32/false
 8681         74/jump-if-= break/disp8
 8682         (check-no-tokens-left %ecx)
 8683         # parse new block and append
 8684         # . var tmp/eax: (handle block)
 8685         68/push 0/imm32
 8686         68/push 0/imm32
 8687         89/<- %eax 4/r32/esp
 8688         # .
 8689         (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 8690         (append-to-block Heap %edi  *eax *(eax+4))
 8691         # . reclaim tmp
 8692         81 0/subop/add %esp 8/imm32
 8693         # .
 8694         e9/jump $parse-mu-block:line-loop/disp32
 8695       }
 8696       # if slice-equal?(word-slice, "}") break
 8697 $parse-mu-block:check-for-end:
 8698       (slice-equal? %edx "}")
 8699       3d/compare-eax-and 0/imm32/false
 8700       0f 85/jump-if-!= break/disp32
 8701       # if slice-ends-with?(word-slice, ":") parse named block and append
 8702       {
 8703 $parse-mu-block:check-for-named-block:
 8704         # . eax = *(word-slice->end-1)
 8705         8b/-> *(edx+4) 0/r32/eax
 8706         48/decrement-eax
 8707         8a/copy-byte *eax 0/r32/AL
 8708         81 4/subop/and %eax 0xff/imm32
 8709         # . if (eax != ':') break
 8710         3d/compare-eax-and 0x3a/imm32/colon
 8711         0f 85/jump-if-!= break/disp32
 8712         # TODO: error-check the rest of 'line'
 8713         #
 8714         # skip ':'
 8715         ff 1/subop/decrement *(edx+4)  # Slice-end
 8716         # var tmp/eax: (handle block)
 8717         68/push 0/imm32
 8718         68/push 0/imm32
 8719         89/<- %eax 4/r32/esp
 8720         #
 8721         (parse-mu-named-block %edx *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 8722         (append-to-block Heap %edi  *eax *(eax+4))
 8723         # reclaim tmp
 8724         81 0/subop/add %esp 8/imm32
 8725         #
 8726         e9/jump $parse-mu-block:line-loop/disp32
 8727       }
 8728       # if slice-equal?(word-slice, "var")
 8729       {
 8730 $parse-mu-block:check-for-var:
 8731         (slice-equal? %edx "var")
 8732         3d/compare-eax-and 0/imm32/false
 8733         74/jump-if-= break/disp8
 8734         # var tmp/eax: (handle block)
 8735         68/push 0/imm32
 8736         68/push 0/imm32
 8737         89/<- %eax 4/r32/esp
 8738         #
 8739         (parse-mu-var-def %ecx *(ebp+0xc) %eax *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
 8740         (append-to-block Heap %edi  *eax *(eax+4))
 8741         # reclaim tmp
 8742         81 0/subop/add %esp 8/imm32
 8743         #
 8744         e9/jump $parse-mu-block:line-loop/disp32
 8745       }
 8746 $parse-mu-block:regular-stmt:
 8747       # otherwise
 8748       # var tmp/eax: (handle block)
 8749       68/push 0/imm32
 8750       68/push 0/imm32
 8751       89/<- %eax 4/r32/esp
 8752       #
 8753       (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 8754       (append-to-block Heap %edi  *eax *(eax+4))
 8755       # reclaim tmp
 8756       81 0/subop/add %esp 8/imm32
 8757       #
 8758       e9/jump loop/disp32
 8759     } # end line loop
 8760     (clean-up-blocks *(ebp+0xc) *Curr-block-depth *(ebp+0x10))
 8761     # decrement *Curr-block-depth
 8762     ff 1/subop/decrement *Curr-block-depth
 8763     # pop(vars)
 8764     (pop *(ebp+0xc))  # => eax
 8765     (pop *(ebp+0xc))  # => eax
 8766     (pop *(ebp+0xc))  # => eax
 8767 $parse-mu-block:end:
 8768     # . reclaim locals
 8769     81 0/subop/add %esp 0x214/imm32
 8770     # . restore registers
 8771     5f/pop-to-edi
 8772     5b/pop-to-ebx
 8773     5a/pop-to-edx
 8774     59/pop-to-ecx
 8775     58/pop-to-eax
 8776     # . epilogue
 8777     89/<- %esp 5/r32/ebp
 8778     5d/pop-to-ebp
 8779     c3/return
 8780 
 8781 $parse-mu-block:abort:
 8782     # error("'{' or '}' should be on its own line, but got '")
 8783     (write-buffered *(ebp+0x18) "'{' or '}' should be on its own line, but got '")
 8784     (rewind-stream %ecx)
 8785     (write-stream-data *(ebp+0x18) %ecx)
 8786     (write-buffered *(ebp+0x18) "'\n")
 8787     (flush *(ebp+0x18))
 8788     (stop *(ebp+0x1c) 1)
 8789     # never gets here
 8790 
 8791 new-block-name:  # fn: (addr function), out: (addr handle var)
 8792     # . prologue
 8793     55/push-ebp
 8794     89/<- %ebp 4/r32/esp
 8795     # . save registers
 8796     50/push-eax
 8797     51/push-ecx
 8798     52/push-edx
 8799     # var n/ecx: int = len(fn->name) + 10 for an int + 2 for '$:'
 8800     8b/-> *(ebp+8) 0/r32/eax
 8801     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 8802     8b/-> *eax 0/r32/eax  # String-size
 8803     05/add-to-eax 0xd/imm32  # 10 + 2 for '$:'
 8804     89/<- %ecx 0/r32/eax
 8805     # var name/edx: (stream byte n)
 8806     29/subtract-from %esp 1/r32/ecx
 8807     ff 6/subop/push %ecx
 8808     68/push 0/imm32/read
 8809     68/push 0/imm32/write
 8810     89/<- %edx 4/r32/esp
 8811     (clear-stream %edx)
 8812     # eax = fn->name
 8813     8b/-> *(ebp+8) 0/r32/eax
 8814     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 8815     # construct result using Next-block-index (and increment it)
 8816     (write %edx "$")
 8817     (write %edx %eax)
 8818     (write %edx ":")
 8819     (write-int32-hex %edx *Next-block-index)
 8820     ff 0/subop/increment *Next-block-index
 8821     # var s/eax: slice = {name->data, name->data + name->write}  (clobbering edx)
 8822     # . eax = name->write
 8823     8b/-> *edx 0/r32/eax
 8824     # . edx = name->data
 8825     8d/copy-address *(edx+0xc) 2/r32/edx
 8826     # . eax = name->write + name->data
 8827     01/add-to %eax 2/r32/edx
 8828     # . push {edx, eax}
 8829     ff 6/subop/push %eax
 8830     ff 6/subop/push %edx
 8831     89/<- %eax 4/r32/esp
 8832     # out = new literal(s)
 8833     (new-literal Heap %eax *(ebp+0xc))
 8834 #?     8b/-> *(ebp+0xc) 0/r32/eax
 8835 #?     (write-buffered Stderr "type allocid in caller after new-literal: ")
 8836 #?     (write-int32-hex-buffered Stderr *(eax+8))
 8837 #?     (write-buffered Stderr " for var ")
 8838 #?     (write-int32-hex-buffered Stderr %eax)
 8839 #?     (write-buffered Stderr Newline)
 8840 #?     (flush Stderr)
 8841 $new-block-name:end:
 8842     # . reclaim locals
 8843     81 0/subop/add %ecx 0xc/imm32  # name.{read/write/len}
 8844     81 0/subop/add %ecx 8/imm32  # slice
 8845     01/add-to %esp 1/r32/ecx
 8846     # . restore registers
 8847     5a/pop-to-edx
 8848     59/pop-to-ecx
 8849     58/pop-to-eax
 8850     # . epilogue
 8851     89/<- %esp 5/r32/ebp
 8852     5d/pop-to-ebp
 8853     c3/return
 8854 
 8855 check-no-tokens-left:  # line: (addr stream byte)
 8856     # . prologue
 8857     55/push-ebp
 8858     89/<- %ebp 4/r32/esp
 8859     # . save registers
 8860     50/push-eax
 8861     51/push-ecx
 8862     # var s/ecx: slice
 8863     68/push 0/imm32/end
 8864     68/push 0/imm32/start
 8865     89/<- %ecx 4/r32/esp
 8866     #
 8867     (next-mu-token *(ebp+8) %ecx)
 8868     # if slice-empty?(s) return
 8869     (slice-empty? %ecx)
 8870     3d/compare-eax-and 0/imm32/false
 8871     75/jump-if-!= $check-no-tokens-left:end/disp8
 8872     # if (slice-starts-with?(s, '#') return
 8873     # . eax = *s->start
 8874     8b/-> *edx 0/r32/eax
 8875     8a/copy-byte *eax 0/r32/AL
 8876     81 4/subop/and %eax 0xff/imm32
 8877     # . if (eax == '#') continue
 8878     3d/compare-eax-and 0x23/imm32/hash
 8879     74/jump-if-= $check-no-tokens-left:end/disp8
 8880     # abort
 8881     (write-buffered Stderr "'{' or '}' should be on its own line, but got '")
 8882     (rewind-stream %ecx)
 8883     (write-stream 2 %ecx)
 8884     (write-buffered Stderr "'\n")
 8885     (flush Stderr)
 8886     # . syscall(exit, 1)
 8887     bb/copy-to-ebx  1/imm32
 8888     e8/call syscall_exit/disp32
 8889     # never gets here
 8890 $check-no-tokens-left:end:
 8891     # . reclaim locals
 8892     81 0/subop/add %esp 8/imm32
 8893     # . restore registers
 8894     59/pop-to-ecx
 8895     58/pop-to-eax
 8896     # . epilogue
 8897     89/<- %esp 5/r32/ebp
 8898     5d/pop-to-ebp
 8899     c3/return
 8900 
 8901 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)
 8902     # pseudocode:
 8903     #   var v: (handle var)
 8904     #   new-literal(name, v)
 8905     #   push(vars, {v, false})
 8906     #   parse-mu-block(in, vars, fn, out)
 8907     #   pop(vars)
 8908     #   out->tag = block
 8909     #   out->var = v
 8910     #
 8911     # . prologue
 8912     55/push-ebp
 8913     89/<- %ebp 4/r32/esp
 8914     # . save registers
 8915     50/push-eax
 8916     51/push-ecx
 8917     57/push-edi
 8918     # var v/ecx: (handle var)
 8919     68/push 0/imm32
 8920     68/push 0/imm32
 8921     89/<- %ecx 4/r32/esp
 8922     #
 8923     (new-literal Heap *(ebp+8) %ecx)
 8924     # push(vars, v)
 8925     (push *(ebp+0x10) *ecx)
 8926     (push *(ebp+0x10) *(ecx+4))
 8927     (push *(ebp+0x10) 0)  # false
 8928     #
 8929     (parse-mu-block *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20))
 8930     # pop v off vars
 8931     (pop *(ebp+0x10))  # => eax
 8932     (pop *(ebp+0x10))  # => eax
 8933     (pop *(ebp+0x10))  # => eax
 8934     # var out-addr/edi: (addr stmt) = lookup(*out)
 8935     8b/-> *(ebp+0x18) 7/r32/edi
 8936     (lookup *edi *(edi+4))  # => eax
 8937     89/<- %edi 0/r32/eax
 8938     # out-addr->tag = named-block
 8939     c7 0/subop/copy *edi 0/imm32/block  # Stmt-tag
 8940     # out-addr->var = v
 8941     8b/-> *ecx 0/r32/eax
 8942     89/<- *(edi+0xc) 0/r32/eax  # Block-var
 8943     8b/-> *(ecx+4) 0/r32/eax
 8944     89/<- *(edi+0x10) 0/r32/eax  # Block-var
 8945 $parse-mu-named-block:end:
 8946     # . reclaim locals
 8947     81 0/subop/add %esp 8/imm32
 8948     # . restore registers
 8949     5f/pop-to-edi
 8950     59/pop-to-ecx
 8951     58/pop-to-eax
 8952     # . epilogue
 8953     89/<- %esp 5/r32/ebp
 8954     5d/pop-to-ebp
 8955     c3/return
 8956 
 8957 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)
 8958     # . prologue
 8959     55/push-ebp
 8960     89/<- %ebp 4/r32/esp
 8961     # . save registers
 8962     50/push-eax
 8963     51/push-ecx
 8964     52/push-edx
 8965     53/push-ebx
 8966     57/push-edi
 8967     # edi = out
 8968     8b/-> *(ebp+0x10) 7/r32/edi
 8969     # var word-slice/ecx: slice
 8970     68/push 0/imm32/end
 8971     68/push 0/imm32/start
 8972     89/<- %ecx 4/r32/esp
 8973     # var v/edx: (handle var)
 8974     68/push 0/imm32
 8975     68/push 0/imm32
 8976     89/<- %edx 4/r32/esp
 8977     # v = parse-var-with-type(next-mu-token(line))
 8978     (next-mu-token *(ebp+8) %ecx)
 8979     (parse-var-with-type %ecx *(ebp+8) %edx *(ebp+0x18) *(ebp+0x1c))
 8980     # var v-addr/eax: (addr var)
 8981     (lookup *edx *(edx+4))  # => eax
 8982     # v->block-depth = *Curr-block-depth
 8983     8b/-> *Curr-block-depth 3/r32/ebx
 8984     89/<- *(eax+0x10) 3/r32/ebx  # Var-block-depth
 8985     # either v has no register and there's no more to this line
 8986     8b/-> *(eax+0x18) 0/r32/eax  # Var-register
 8987     3d/compare-eax-and 0/imm32
 8988     {
 8989       75/jump-if-!= break/disp8
 8990       # TODO: disallow vars of type 'byte' on the stack
 8991       # ensure that there's nothing else on this line
 8992       (next-mu-token *(ebp+8) %ecx)
 8993       (slice-empty? %ecx)  # => eax
 8994       3d/compare-eax-and 0/imm32/false
 8995       0f 84/jump-if-= $parse-mu-var-def:error2/disp32
 8996       #
 8997       (new-var-def Heap  *edx *(edx+4)  %edi)
 8998       e9/jump $parse-mu-var-def:update-vars/disp32
 8999     }
 9000     # or v has a register and there's more to this line
 9001     {
 9002       0f 84/jump-if-= break/disp32
 9003       # TODO: disallow vars of type 'byte' in registers 'esi' or 'edi'
 9004       # TODO: vars of type 'byte' should only be initialized by clearing to 0
 9005       # ensure that the next word is '<-'
 9006       (next-mu-token *(ebp+8) %ecx)
 9007       (slice-equal? %ecx "<-")  # => eax
 9008       3d/compare-eax-and 0/imm32/false
 9009       0f 84/jump-if-= $parse-mu-var-def:error1/disp32
 9010       #
 9011       (new-reg-var-def Heap  *edx *(edx+4)  %edi)
 9012       (lookup *edi *(edi+4))  # => eax
 9013       (add-operation-and-inputs-to-stmt %eax *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 9014     }
 9015 $parse-mu-var-def:update-vars:
 9016     # push 'v' at end of function
 9017     (push *(ebp+0xc) *edx)
 9018     (push *(ebp+0xc) *(edx+4))
 9019     (push *(ebp+0xc) 0)  # Live-var-register-spilled is unused during parsing
 9020 $parse-mu-var-def:end:
 9021     # . reclaim locals
 9022     81 0/subop/add %esp 0x10/imm32
 9023     # . restore registers
 9024     5f/pop-to-edi
 9025     5b/pop-to-ebx
 9026     5a/pop-to-edx
 9027     59/pop-to-ecx
 9028     58/pop-to-eax
 9029     # . epilogue
 9030     89/<- %esp 5/r32/ebp
 9031     5d/pop-to-ebp
 9032     c3/return
 9033 
 9034 $parse-mu-var-def:error1:
 9035     (rewind-stream *(ebp+8))
 9036     # error("register variable requires a valid instruction to initialize but got '" line "'\n")
 9037     (write-buffered *(ebp+0x18) "register variable requires a valid instruction to initialize but got '")
 9038     (flush *(ebp+0x18))
 9039     (write-stream-data *(ebp+0x18) *(ebp+8))
 9040     (write-buffered *(ebp+0x18) "'\n")
 9041     (flush *(ebp+0x18))
 9042     (stop *(ebp+0x1c) 1)
 9043     # never gets here
 9044 
 9045 $parse-mu-var-def:error2:
 9046     (rewind-stream *(ebp+8))
 9047     # error("fn " fn ": var " var ": variables on the stack can't take an initializer\n")
 9048     (write-buffered *(ebp+0x18) "fn ")
 9049     8b/-> *(ebp+0x14) 0/r32/eax
 9050     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9051     (write-buffered *(ebp+0x18) %eax)
 9052     (write-buffered *(ebp+0x18) ": var ")
 9053     # var v-addr/eax: (addr var) = lookup(v)
 9054     (lookup *edx *(edx+4))  # => eax
 9055     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9056     (write-buffered *(ebp+0x18) %eax)
 9057     (write-buffered *(ebp+0x18) ": variables on the stack can't take an initializer\n")
 9058     (flush *(ebp+0x18))
 9059     (stop *(ebp+0x1c) 1)
 9060     # never gets here
 9061 
 9062 test-parse-mu-var-def:
 9063     # 'var n: int'
 9064     # . prologue
 9065     55/push-ebp
 9066     89/<- %ebp 4/r32/esp
 9067     # setup
 9068     (clear-stream _test-input-stream)
 9069     (write _test-input-stream "n: int\n")  # caller has consumed the 'var'
 9070     c7 0/subop/copy *Curr-block-depth 1/imm32
 9071     # var out/esi: (handle stmt)
 9072     68/push 0/imm32
 9073     68/push 0/imm32
 9074     89/<- %esi 4/r32/esp
 9075     # var vars/ecx: (stack (addr var) 16)
 9076     81 5/subop/subtract %esp 0xc0/imm32
 9077     68/push 0xc0/imm32/size
 9078     68/push 0/imm32/top
 9079     89/<- %ecx 4/r32/esp
 9080     (clear-stack %ecx)
 9081     # convert
 9082     (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0)
 9083     # var out-addr/esi: (addr stmt)
 9084     (lookup *esi *(esi+4))  # => eax
 9085     89/<- %esi 0/r32/eax
 9086     #
 9087     (check-ints-equal *esi 2 "F - test-parse-mu-var-def/tag")  # Stmt-tag is var-def
 9088     # var v/ecx: (addr var) = lookup(out->var)
 9089     (lookup *(esi+4) *(esi+8))  # Vardef-var Vardef-var => eax
 9090     89/<- %ecx 0/r32/eax
 9091     # v->name
 9092     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 9093     (check-strings-equal %eax "n" "F - test-parse-mu-var-def/var-name")
 9094     # v->register
 9095     (check-ints-equal *(ecx+0x18) 0 "F - test-parse-mu-var-def/var-register")  # Var-register
 9096     # v->block-depth
 9097     (check-ints-equal *(ecx+0x10) 1 "F - test-parse-mu-var-def/output-block-depth")  # Var-block-depth
 9098     # v->type == int
 9099     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 9100     (check-ints-equal *eax 1 "F - test-parse-mu-var-def/var-type:0")  # Type-tree-is-atom
 9101     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-var-def/var-type:1")  # Type-tree-value
 9102     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-var-def/var-type:2")  # Type-tree-right
 9103     # . epilogue
 9104     89/<- %esp 5/r32/ebp
 9105     5d/pop-to-ebp
 9106     c3/return
 9107 
 9108 test-parse-mu-reg-var-def:
 9109     # 'var n/eax: int <- copy 0'
 9110     # . prologue
 9111     55/push-ebp
 9112     89/<- %ebp 4/r32/esp
 9113     # setup
 9114     (clear-stream _test-input-stream)
 9115     (write _test-input-stream "n/eax: int <- copy 0\n")  # caller has consumed the 'var'
 9116     c7 0/subop/copy *Curr-block-depth 1/imm32
 9117     # var out/esi: (handle stmt)
 9118     68/push 0/imm32
 9119     68/push 0/imm32
 9120     89/<- %esi 4/r32/esp
 9121     # var vars/ecx: (stack (addr var) 16)
 9122     81 5/subop/subtract %esp 0xc0/imm32
 9123     68/push 0xc0/imm32/size
 9124     68/push 0/imm32/top
 9125     89/<- %ecx 4/r32/esp
 9126     (clear-stack %ecx)
 9127     # convert
 9128     (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0)
 9129     # var out-addr/esi: (addr stmt)
 9130     (lookup *esi *(esi+4))  # => eax
 9131     89/<- %esi 0/r32/eax
 9132     #
 9133     (check-ints-equal *esi 3 "F - test-parse-mu-reg-var-def/tag")  # Stmt-tag is reg-var-def
 9134     # var v/ecx: (addr var) = lookup(out->outputs->value)
 9135     # . eax: (addr stmt-var) = lookup(out->outputs)
 9136     (lookup *(esi+0x14) *(esi+0x18))  # Regvardef-outputs Regvardef-outputs => eax
 9137     # .
 9138     (check-ints-equal *(eax+8) 0 "F - test-parse-mu-reg-var-def/single-output")  # Stmt-var-next
 9139     # . eax: (addr var) = lookup(eax->value)
 9140     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9141     # . ecx = eax
 9142     89/<- %ecx 0/r32/eax
 9143     # v->name
 9144     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 9145     (check-strings-equal %eax "n" "F - test-parse-mu-reg-var-def/output-name")  # Var-name
 9146     # v->register
 9147     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 9148     (check-strings-equal %eax "eax" "F - test-parse-mu-reg-var-def/output-register")
 9149     # v->block-depth
 9150     (check-ints-equal *(ecx+0x10) 1 "F - test-parse-mu-reg-var-def/output-block-depth")  # Var-block-depth
 9151     # v->type == int
 9152     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 9153     (check-ints-equal *eax 1 "F - test-parse-mu-reg-var-def/output-type:0")  # Type-tree-is-atom
 9154     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-reg-var-def/output-type:1")  # Type-tree-value
 9155     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-reg-var-def/output-type:2")  # Type-tree-right
 9156     # . epilogue
 9157     89/<- %esp 5/r32/ebp
 9158     5d/pop-to-ebp
 9159     c3/return
 9160 
 9161 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)
 9162     # Carefully push any outputs on the vars stack _after_ reading the inputs
 9163     # that may conflict with them.
 9164     #
 9165     # The only situation in which outputs are pushed here (when it's not a
 9166     # 'var' vardef stmt), and so can possibly conflict with inputs, is if the
 9167     # output is a function output.
 9168     #
 9169     # pseudocode:
 9170     #   var name: slice
 9171     #   allocate(Heap, Stmt-size, out)
 9172     #   var out-addr: (addr stmt) = lookup(*out)
 9173     #   out-addr->tag = stmt
 9174     #   if stmt-has-outputs?(line)
 9175     #     while true
 9176     #       name = next-mu-token(line)
 9177     #       if (name == '<-') break
 9178     #       assert(is-identifier?(name))
 9179     #       var v: (handle var) = lookup-var-or-find-in-fn-outputs(name, vars, fn)
 9180     #       out-addr->outputs = append(v, out-addr->outputs)
 9181     #   add-operation-and-inputs-to-stmt(out-addr, line, vars)
 9182     #   for output in stmt->outputs:
 9183     #     maybe-define-var(output, vars)
 9184     #
 9185     # . prologue
 9186     55/push-ebp
 9187     89/<- %ebp 4/r32/esp
 9188     # . save registers
 9189     50/push-eax
 9190     51/push-ecx
 9191     52/push-edx
 9192     53/push-ebx
 9193     57/push-edi
 9194     # var name/ecx: slice
 9195     68/push 0/imm32/end
 9196     68/push 0/imm32/start
 9197     89/<- %ecx 4/r32/esp
 9198     # var is-deref?/edx: boolean = false
 9199     ba/copy-to-edx 0/imm32/false
 9200     # var v: (handle var)
 9201     68/push 0/imm32
 9202     68/push 0/imm32
 9203     89/<- %ebx 4/r32/esp
 9204     #
 9205     (allocate Heap *Stmt-size *(ebp+0x14))
 9206     # var out-addr/edi: (addr stmt) = lookup(*out)
 9207     8b/-> *(ebp+0x14) 7/r32/edi
 9208     (lookup *edi *(edi+4))  # => eax
 9209     89/<- %edi 0/r32/eax
 9210     # out-addr->tag = 1/stmt
 9211     c7 0/subop/copy *edi 1/imm32/stmt1  # Stmt-tag
 9212     {
 9213       (stmt-has-outputs? *(ebp+8))
 9214       3d/compare-eax-and 0/imm32/false
 9215       0f 84/jump-if-= break/disp32
 9216       {
 9217 $parse-mu-stmt:read-outputs:
 9218         # name = next-mu-token(line)
 9219         (next-mu-token *(ebp+8) %ecx)
 9220         # if slice-empty?(word-slice) break
 9221         (slice-empty? %ecx)  # => eax
 9222         3d/compare-eax-and 0/imm32/false
 9223         0f 85/jump-if-!= break/disp32
 9224         # if (name == "<-") break
 9225         (slice-equal? %ecx "<-")  # => eax
 9226         3d/compare-eax-and 0/imm32/false
 9227         0f 85/jump-if-!= break/disp32
 9228         # is-deref? = false
 9229         ba/copy-to-edx 0/imm32/false
 9230         # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
 9231         8b/-> *ecx 0/r32/eax  # Slice-start
 9232         8a/copy-byte *eax 0/r32/AL
 9233         81 4/subop/and %eax 0xff/imm32
 9234         3d/compare-eax-and 0x2a/imm32/asterisk
 9235         {
 9236           75/jump-if-!= break/disp8
 9237           ff 0/subop/increment *ecx
 9238           ba/copy-to-edx 1/imm32/true
 9239         }
 9240         # assert(is-identifier?(name))
 9241         (is-identifier? %ecx)  # => eax
 9242         3d/compare-eax-and 0/imm32/false
 9243         0f 84/jump-if-= $parse-mu-stmt:abort/disp32
 9244         #
 9245         (lookup-var-or-find-in-fn-outputs %ecx *(ebp+0xc) *(ebp+0x10) %ebx *(ebp+0x18) *(ebp+0x1c))
 9246         8d/copy-address *(edi+0x14) 0/r32/eax  # Stmt1-outputs
 9247         (append-stmt-var Heap  *ebx *(ebx+4)  *(edi+0x14) *(edi+0x18)  %edx  %eax)  # Stmt1-outputs
 9248         #
 9249         e9/jump loop/disp32
 9250       }
 9251     }
 9252     (add-operation-and-inputs-to-stmt %edi *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
 9253 $parse-mu-stmt:define-outputs:
 9254     # var output/edi: (addr stmt-var) = lookup(out-addr->outputs)
 9255     (lookup *(edi+0x14) *(edi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
 9256     89/<- %edi 0/r32/eax
 9257     {
 9258 $parse-mu-stmt:define-outputs-loop:
 9259       # if (output == null) break
 9260       81 7/subop/compare %edi 0/imm32
 9261       74/jump-if-= break/disp8
 9262       #
 9263       (maybe-define-var *edi *(edi+4)  *(ebp+0xc))  # if output is a deref, then it's already been defined,
 9264                                                     # and must be in vars. This call will be a no-op, but safe.
 9265       # output = output->next
 9266       (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
 9267       89/<- %edi 0/r32/eax
 9268       #
 9269       eb/jump loop/disp8
 9270     }
 9271 $parse-mu-stmt:end:
 9272     # . reclaim locals
 9273     81 0/subop/add %esp 0x10/imm32
 9274     # . restore registers
 9275     5f/pop-to-edi
 9276     5b/pop-to-ebx
 9277     5a/pop-to-edx
 9278     59/pop-to-ecx
 9279     58/pop-to-eax
 9280     # . epilogue
 9281     89/<- %esp 5/r32/ebp
 9282     5d/pop-to-ebp
 9283     c3/return
 9284 
 9285 $parse-mu-stmt:abort:
 9286     # error("invalid identifier '" name "'\n")
 9287     (write-buffered *(ebp+0x18) "invalid identifier '")
 9288     (write-slice-buffered *(ebp+0x18) %ecx)
 9289     (write-buffered *(ebp+0x18) "'\n")
 9290     (flush *(ebp+0x18))
 9291     (stop *(ebp+0x1c) 1)
 9292     # never gets here
 9293 
 9294 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)
 9295     # pseudocode:
 9296     #   stmt->name = slice-to-string(next-mu-token(line))
 9297     #   while true
 9298     #     name = next-mu-token(line)
 9299     #     v = lookup-var-or-literal(name)
 9300     #     stmt->inouts = append(v, stmt->inouts)
 9301     #
 9302     # . prologue
 9303     55/push-ebp
 9304     89/<- %ebp 4/r32/esp
 9305     # . save registers
 9306     50/push-eax
 9307     51/push-ecx
 9308     52/push-edx
 9309     53/push-ebx
 9310     56/push-esi
 9311     57/push-edi
 9312     # edi = stmt
 9313     8b/-> *(ebp+8) 7/r32/edi
 9314     # var name/ecx: slice
 9315     68/push 0/imm32/end
 9316     68/push 0/imm32/start
 9317     89/<- %ecx 4/r32/esp
 9318     # var is-deref?/edx: boolean = false
 9319     ba/copy-to-edx 0/imm32/false
 9320     # var v/esi: (handle var)
 9321     68/push 0/imm32
 9322     68/push 0/imm32
 9323     89/<- %esi 4/r32/esp
 9324 $add-operation-and-inputs-to-stmt:read-operation:
 9325     (next-mu-token *(ebp+0xc) %ecx)
 9326     8d/copy-address *(edi+4) 0/r32/eax  # Stmt1-operation or Regvardef-operationStmt1-operation or Regvardef-operation
 9327     (slice-to-string Heap %ecx %eax)
 9328     # var is-get?/ebx: boolean = (name == "get")
 9329     (slice-equal? %ecx "get")  # => eax
 9330     89/<- %ebx 0/r32/eax
 9331     {
 9332 $add-operation-and-inputs-to-stmt:read-inouts:
 9333       # name = next-mu-token(line)
 9334       (next-mu-token *(ebp+0xc) %ecx)
 9335       # if slice-empty?(word-slice) break
 9336       (slice-empty? %ecx)  # => eax
 9337       3d/compare-eax-and 0/imm32/false
 9338       0f 85/jump-if-!= break/disp32
 9339       # if (name == "<-") abort
 9340       (slice-equal? %ecx "<-")
 9341       3d/compare-eax-and 0/imm32/false
 9342       0f 85/jump-if-!= $add-operation-and-inputs-to-stmt:abort/disp32
 9343       # if (is-get? && second operand) lookup or create offset
 9344       {
 9345         81 7/subop/compare %ebx 0/imm32/false
 9346         74/jump-if-= break/disp8
 9347         (lookup *(edi+0xc) *(edi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9348         3d/compare-eax-and 0/imm32
 9349         74/jump-if-= break/disp8
 9350         (lookup-or-create-constant %eax %ecx %esi)
 9351 #?         (lookup *esi *(esi+4))
 9352 #?         (write-buffered Stderr "creating new output var ")
 9353 #?         (write-int32-hex-buffered Stderr %eax)
 9354 #?         (write-buffered Stderr " for field called ")
 9355 #?         (write-slice-buffered Stderr %ecx)
 9356 #?         (write-buffered Stderr "; var name ")
 9357 #?         (lookup *eax *(eax+4))  # Var-name
 9358 #?         (write-buffered Stderr %eax)
 9359 #?         (write-buffered Stderr Newline)
 9360 #?         (flush Stderr)
 9361         e9/jump $add-operation-and-inputs-to-stmt:save-var/disp32
 9362       }
 9363       # is-deref? = false
 9364       ba/copy-to-edx 0/imm32/false
 9365       # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
 9366       8b/-> *ecx 0/r32/eax  # Slice-start
 9367       8a/copy-byte *eax 0/r32/AL
 9368       81 4/subop/and %eax 0xff/imm32
 9369       3d/compare-eax-and 0x2a/imm32/asterisk
 9370       {
 9371         75/jump-if-!= break/disp8
 9372 $add-operation-and-inputs-to-stmt:inout-is-deref:
 9373         ff 0/subop/increment *ecx
 9374         ba/copy-to-edx 1/imm32/true
 9375       }
 9376       (lookup-var-or-literal %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 9377 $add-operation-and-inputs-to-stmt:save-var:
 9378       8d/copy-address *(edi+0xc) 0/r32/eax
 9379       (append-stmt-var Heap  *esi *(esi+4)  *(edi+0xc) *(edi+0x10)  %edx  %eax)  # Stmt1-inouts or Regvardef-inouts
 9380       #
 9381       e9/jump loop/disp32
 9382     }
 9383 $add-operation-and-inputs-to-stmt:end:
 9384     # . reclaim locals
 9385     81 0/subop/add %esp 0x10/imm32
 9386     # . restore registers
 9387     5f/pop-to-edi
 9388     5e/pop-to-esi
 9389     5b/pop-to-ebx
 9390     5a/pop-to-edx
 9391     59/pop-to-ecx
 9392     58/pop-to-eax
 9393     # . epilogue
 9394     89/<- %esp 5/r32/ebp
 9395     5d/pop-to-ebp
 9396     c3/return
 9397 
 9398 $add-operation-and-inputs-to-stmt:abort:
 9399     # error("fn ___: invalid identifier in '" line "'\n")
 9400     (write-buffered *(ebp+0x18) "fn ")
 9401     8b/-> *(ebp+0x14) 0/r32/eax
 9402     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9403     (write-buffered *(ebp+0x18) %eax)
 9404     (rewind-stream *(ebp+0xc))
 9405     (write-buffered *(ebp+0x18) ": invalid identifier in '")
 9406     (write-stream-data *(ebp+0x18) *(ebp+0xc))
 9407     (write-buffered *(ebp+0x18) "'\n")
 9408     (flush *(ebp+0x18))
 9409     (stop *(ebp+0x1c) 1)
 9410     # never gets here
 9411 
 9412 stmt-has-outputs?:  # line: (addr stream byte) -> result/eax: boolean
 9413     # . prologue
 9414     55/push-ebp
 9415     89/<- %ebp 4/r32/esp
 9416     # . save registers
 9417     51/push-ecx
 9418     # var word-slice/ecx: slice
 9419     68/push 0/imm32/end
 9420     68/push 0/imm32/start
 9421     89/<- %ecx 4/r32/esp
 9422     # result = false
 9423     b8/copy-to-eax 0/imm32/false
 9424     (rewind-stream *(ebp+8))
 9425     {
 9426       (next-mu-token *(ebp+8) %ecx)
 9427       # if slice-empty?(word-slice) break
 9428       (slice-empty? %ecx)
 9429       3d/compare-eax-and 0/imm32/false
 9430       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
 9431       0f 85/jump-if-!= break/disp32
 9432       # if slice-starts-with?(word-slice, '#') break
 9433       # . eax = *word-slice->start
 9434       8b/-> *ecx 0/r32/eax
 9435       8a/copy-byte *eax 0/r32/AL
 9436       81 4/subop/and %eax 0xff/imm32
 9437       # . if (eax == '#') break
 9438       3d/compare-eax-and 0x23/imm32/hash
 9439       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
 9440       0f 84/jump-if-= break/disp32
 9441       # if slice-equal?(word-slice, '<-') return true
 9442       (slice-equal? %ecx "<-")
 9443       3d/compare-eax-and 0/imm32/false
 9444       74/jump-if-= loop/disp8
 9445       b8/copy-to-eax 1/imm32/true
 9446     }
 9447 $stmt-has-outputs:end:
 9448     (rewind-stream *(ebp+8))
 9449     # . reclaim locals
 9450     81 0/subop/add %esp 8/imm32
 9451     # . restore registers
 9452     59/pop-to-ecx
 9453     # . epilogue
 9454     89/<- %esp 5/r32/ebp
 9455     5d/pop-to-ebp
 9456     c3/return
 9457 
 9458 # if 'name' starts with a digit, create a new literal var for it
 9459 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found
 9460 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)
 9461     # . prologue
 9462     55/push-ebp
 9463     89/<- %ebp 4/r32/esp
 9464     # . save registers
 9465     50/push-eax
 9466     51/push-ecx
 9467     56/push-esi
 9468     # esi = name
 9469     8b/-> *(ebp+8) 6/r32/esi
 9470     # if slice-empty?(name) abort
 9471     (slice-empty? %esi)  # => eax
 9472     3d/compare-eax-and 0/imm32/false
 9473     0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32
 9474     # var c/ecx: byte = *name->start
 9475     8b/-> *esi 1/r32/ecx
 9476     8a/copy-byte *ecx 1/r32/CL
 9477     81 4/subop/and %ecx 0xff/imm32
 9478     # if is-decimal-digit?(c) return new var(name)
 9479     {
 9480       (is-decimal-digit? %ecx)  # => eax
 9481       3d/compare-eax-and 0/imm32/false
 9482       74/jump-if-= break/disp8
 9483 $lookup-var-or-literal:literal:
 9484       (new-literal-integer Heap %esi *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 9485       eb/jump $lookup-var-or-literal:end/disp8
 9486     }
 9487     # else if (c == '"') return new var(name)
 9488     {
 9489       81 7/subop/compare %ecx 0x22/imm32/dquote
 9490       75/jump-if-!= break/disp8
 9491 $lookup-var-or-literal:literal-string:
 9492       (new-literal Heap %esi *(ebp+0x10))
 9493       eb/jump $lookup-var-or-literal:end/disp8
 9494     }
 9495     # otherwise return lookup-var(name, vars)
 9496     {
 9497 $lookup-var-or-literal:var:
 9498       (lookup-var %esi *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 9499     }
 9500 $lookup-var-or-literal:end:
 9501     # . restore registers
 9502     5e/pop-to-esi
 9503     59/pop-to-ecx
 9504     58/pop-to-eax
 9505     # . epilogue
 9506     89/<- %esp 5/r32/ebp
 9507     5d/pop-to-ebp
 9508     c3/return
 9509 
 9510 $lookup-var-or-literal:abort:
 9511     (write-buffered *(ebp+0x18) "fn ")
 9512     8b/-> *(ebp+0x14) 0/r32/eax
 9513     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9514     (write-buffered *(ebp+0x18) %eax)
 9515     (write-buffered *(ebp+0x18) ": empty variable!")
 9516     (flush *(ebp+0x18))
 9517     (stop *(ebp+0x1c) 1)
 9518     # never gets here
 9519 
 9520 # return first 'name' from the top (back) of 'vars' and abort if not found
 9521 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)
 9522     # . prologue
 9523     55/push-ebp
 9524     89/<- %ebp 4/r32/esp
 9525     # . save registers
 9526     50/push-eax
 9527     #
 9528     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 9529     # if (*out == 0) abort
 9530     8b/-> *(ebp+0x10) 0/r32/eax
 9531     81 7/subop/compare *eax 0/imm32
 9532     74/jump-if-= $lookup-var:abort/disp8
 9533 $lookup-var:end:
 9534     # . restore registers
 9535     58/pop-to-eax
 9536     # . epilogue
 9537     89/<- %esp 5/r32/ebp
 9538     5d/pop-to-ebp
 9539     c3/return
 9540 
 9541 $lookup-var:abort:
 9542     (write-buffered *(ebp+0x18) "fn ")
 9543     8b/-> *(ebp+0x14) 0/r32/eax
 9544     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9545     (write-buffered *(ebp+0x18) %eax)
 9546     (write-buffered *(ebp+0x18) ": unknown variable '")
 9547     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 9548     (write-buffered *(ebp+0x18) "'\n")
 9549     (flush *(ebp+0x18))
 9550     (stop *(ebp+0x1c) 1)
 9551     # never gets here
 9552 
 9553 # return first 'name' from the top (back) of 'vars', and 0/null if not found
 9554 # ensure that 'name' if in a register is the topmost variable in that register
 9555 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)
 9556     # pseudocode:
 9557     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
 9558     #   var min = vars->data
 9559     #   while curr >= min
 9560     #     var v: (handle var) = *curr
 9561     #     if v->name == name
 9562     #       return
 9563     #     curr -= 12
 9564     #
 9565     # . prologue
 9566     55/push-ebp
 9567     89/<- %ebp 4/r32/esp
 9568     # . save registers
 9569     50/push-eax
 9570     51/push-ecx
 9571     52/push-edx
 9572     53/push-ebx
 9573     56/push-esi
 9574     57/push-edi
 9575     # clear out
 9576     (zero-out *(ebp+0x10) *Handle-size)
 9577     # esi = vars
 9578     8b/-> *(ebp+0xc) 6/r32/esi
 9579     # ebx = vars->top
 9580     8b/-> *esi 3/r32/ebx
 9581     # if (vars->top > vars->size) abort
 9582     3b/compare<- *(esi+4) 0/r32/eax
 9583     0f 8f/jump-if-> $lookup-var-helper:error1/disp32
 9584     # var min/edx: (addr handle var) = vars->data
 9585     8d/copy-address *(esi+8) 2/r32/edx
 9586     # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
 9587     8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
 9588     # var var-in-reg/edi: 8 addrs
 9589     68/push 0/imm32
 9590     68/push 0/imm32
 9591     68/push 0/imm32
 9592     68/push 0/imm32
 9593     68/push 0/imm32
 9594     68/push 0/imm32
 9595     68/push 0/imm32
 9596     68/push 0/imm32
 9597     89/<- %edi 4/r32/esp
 9598     {
 9599 $lookup-var-helper:loop:
 9600       # if (curr < min) return
 9601       39/compare %ebx 2/r32/edx
 9602       0f 82/jump-if-addr< break/disp32
 9603       # var v/ecx: (addr var) = lookup(*curr)
 9604       (lookup *ebx *(ebx+4))  # => eax
 9605       89/<- %ecx 0/r32/eax
 9606       # var vn/eax: (addr array byte) = lookup(v->name)
 9607       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 9608       # if (vn == name) return curr
 9609       (slice-equal? *(ebp+8) %eax)  # => eax
 9610       3d/compare-eax-and 0/imm32/false
 9611       {
 9612         74/jump-if-= break/disp8
 9613 $lookup-var-helper:found:
 9614         # var vr/eax: (addr array byte) = lookup(v->register)
 9615         (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 9616         3d/compare-eax-and 0/imm32
 9617         {
 9618           74/jump-if-= break/disp8
 9619 $lookup-var-helper:found-register:
 9620           # var reg/eax: int = get(Registers, vr)
 9621           (get Mu-registers %eax 0xc "Mu-registers")  # => eax
 9622           8b/-> *eax 0/r32/eax
 9623           # if (var-in-reg[reg]) error
 9624           8b/-> *(edi+eax<<2) 0/r32/eax
 9625           3d/compare-eax-and 0/imm32
 9626           0f 85/jump-if-!= $lookup-var-helper:error2/disp32
 9627         }
 9628 $lookup-var-helper:return:
 9629         # esi = out
 9630         8b/-> *(ebp+0x10) 6/r32/esi
 9631         # *out = *curr
 9632         8b/-> *ebx 0/r32/eax
 9633         89/<- *esi 0/r32/eax
 9634         8b/-> *(ebx+4) 0/r32/eax
 9635         89/<- *(esi+4) 0/r32/eax
 9636         # return
 9637         eb/jump $lookup-var-helper:end/disp8
 9638       }
 9639       # 'name' not yet found; update var-in-reg if v in register
 9640       # . var vr/eax: (addr array byte) = lookup(v->register)
 9641       (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 9642       # . if (var == 0) continue
 9643       3d/compare-eax-and 0/imm32
 9644       74/jump-if-= $lookup-var-helper:continue/disp8
 9645       # . var reg/eax: int = get(Registers, vr)
 9646       (get Mu-registers %eax 0xc "Mu-registers")  # => eax
 9647       8b/-> *eax 0/r32/eax
 9648       # . if (var-in-reg[reg] == 0) var-in-reg[reg] = v
 9649       81 7/subop/compare *(edi+eax<<2) 0/imm32
 9650       75/jump-if-!= $lookup-var-helper:continue/disp8
 9651       89/<- *(edi+eax<<2) 1/r32/ecx
 9652 $lookup-var-helper:continue:
 9653       # curr -= 12
 9654       81 5/subop/subtract %ebx 0xc/imm32
 9655       e9/jump loop/disp32
 9656     }
 9657 $lookup-var-helper:end:
 9658     # . reclaim locals
 9659     81 0/subop/add %esp 0x20/imm32
 9660     # . restore registers
 9661     5f/pop-to-edi
 9662     5e/pop-to-esi
 9663     5b/pop-to-ebx
 9664     5a/pop-to-edx
 9665     59/pop-to-ecx
 9666     58/pop-to-eax
 9667     # . epilogue
 9668     89/<- %esp 5/r32/ebp
 9669     5d/pop-to-ebp
 9670     c3/return
 9671 
 9672 $lookup-var-helper:error1:
 9673     (write-buffered *(ebp+0x18) "fn ")
 9674     8b/-> *(ebp+0x14) 0/r32/eax
 9675     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9676     (write-buffered *(ebp+0x18) %eax)
 9677     (write-buffered *(ebp+0x18) ": malformed stack when looking up '")
 9678     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 9679     (write-buffered *(ebp+0x18) "'\n")
 9680     (flush *(ebp+0x18))
 9681     (stop *(ebp+0x1c) 1)
 9682     # never gets here
 9683 
 9684 $lookup-var-helper:error2:
 9685     # eax contains the conflicting var at this point
 9686     (write-buffered *(ebp+0x18) "fn ")
 9687     50/push-eax
 9688     8b/-> *(ebp+0x14) 0/r32/eax
 9689     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9690     (write-buffered *(ebp+0x18) %eax)
 9691     58/pop-eax
 9692     (write-buffered *(ebp+0x18) ": register ")
 9693     50/push-eax
 9694     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
 9695     (write-buffered *(ebp+0x18) %eax)
 9696     58/pop-to-eax
 9697     (write-buffered *(ebp+0x18) " reads var '")
 9698     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 9699     (write-buffered *(ebp+0x18) "' after writing var '")
 9700     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9701     (write-buffered *(ebp+0x18) %eax)
 9702     (write-buffered *(ebp+0x18) "'\n")
 9703     (flush *(ebp+0x18))
 9704     (stop *(ebp+0x1c) 1)
 9705     # never gets here
 9706 
 9707 dump-vars:  # vars: (addr stack live-var)
 9708     # pseudocode:
 9709     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
 9710     #   var min = vars->data
 9711     #   while curr >= min
 9712     #     var v: (handle var) = *curr
 9713     #     print v
 9714     #     curr -= 12
 9715     #
 9716     # . prologue
 9717     55/push-ebp
 9718     89/<- %ebp 4/r32/esp
 9719     # . save registers
 9720     52/push-edx
 9721     53/push-ebx
 9722     56/push-esi
 9723     # esi = vars
 9724     8b/-> *(ebp+8) 6/r32/esi
 9725     # ebx = vars->top
 9726     8b/-> *esi 3/r32/ebx
 9727     # var min/edx: (addr handle var) = vars->data
 9728     8d/copy-address *(esi+8) 2/r32/edx
 9729     # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
 9730     8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
 9731     {
 9732 $dump-vars:loop:
 9733       # if (curr < min) return
 9734       39/compare %ebx 2/r32/edx
 9735       0f 82/jump-if-addr< break/disp32
 9736       #
 9737       (write-buffered Stderr "  var@")
 9738       (dump-var 2 %ebx)
 9739       # curr -= 12
 9740       81 5/subop/subtract %ebx 0xc/imm32
 9741       e9/jump loop/disp32
 9742     }
 9743 $dump-vars:end:
 9744     # . restore registers
 9745     5e/pop-to-esi
 9746     5b/pop-to-ebx
 9747     5a/pop-to-edx
 9748     # . epilogue
 9749     89/<- %esp 5/r32/ebp
 9750     5d/pop-to-ebp
 9751     c3/return
 9752 
 9753 == data
 9754 # Like Registers, but no esp or ebp
 9755 Mu-registers:  # (addr stream {(handle array byte), int})
 9756   # a table is a stream
 9757   0x48/imm32/write
 9758   0/imm32/read
 9759   0x48/imm32/length
 9760   # data
 9761   # it is perfectly ok to use fake alloc-ids -- as long as you never try to reclaim them
 9762   0x11/imm32/alloc-id $Mu-register-eax/imm32 0/imm32
 9763   0x11/imm32/alloc-id $Mu-register-ecx/imm32 1/imm32
 9764   0x11/imm32/alloc-id $Mu-register-edx/imm32 2/imm32
 9765   0x11/imm32/alloc-id $Mu-register-ebx/imm32 3/imm32
 9766   0x11/imm32/alloc-id $Mu-register-esi/imm32 6/imm32
 9767   0x11/imm32/alloc-id $Mu-register-edi/imm32 7/imm32
 9768 
 9769 $Mu-register-eax:
 9770   0x11/imm32/alloc-id
 9771   3/imm32/size
 9772   0x65/e 0x61/a 0x78/x
 9773 
 9774 $Mu-register-ecx:
 9775   0x11/imm32/alloc-id
 9776   3/imm32/size
 9777   0x65/e 0x63/c 0x78/x
 9778 
 9779 $Mu-register-edx:
 9780   0x11/imm32/alloc-id
 9781   3/imm32/size
 9782   0x65/e 0x64/d 0x78/x
 9783 
 9784 $Mu-register-ebx:
 9785   0x11/imm32/alloc-id
 9786   3/imm32/size
 9787   0x65/e 0x62/b 0x78/x
 9788 
 9789 $Mu-register-esi:
 9790   0x11/imm32/alloc-id
 9791   3/imm32/size
 9792   0x65/e 0x73/s 0x69/i
 9793 
 9794 $Mu-register-edi:
 9795   0x11/imm32/alloc-id
 9796   3/imm32/size
 9797   0x65/e 0x64/d 0x69/i
 9798 
 9799 == code
 9800 
 9801 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found
 9802 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)
 9803     # . prologue
 9804     55/push-ebp
 9805     89/<- %ebp 4/r32/esp
 9806     # . save registers
 9807     50/push-eax
 9808     #
 9809     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))  # arg order slightly different; 'fn' is deemphasized
 9810     {
 9811       # if (out != 0) return
 9812       8b/-> *(ebp+0x14) 0/r32/eax
 9813       81 7/subop/compare *eax 0/imm32
 9814       75/jump-if-!= break/disp8
 9815       # if name is one of fn's outputs, return it
 9816       (find-in-function-outputs *(ebp+0x10) *(ebp+8) *(ebp+0x14))
 9817       8b/-> *(ebp+0x14) 0/r32/eax
 9818       81 7/subop/compare *eax 0/imm32
 9819       # otherwise abort
 9820       0f 84/jump-if-= $lookup-or-define-var:abort/disp32
 9821     }
 9822 $lookup-or-define-var:end:
 9823     # . restore registers
 9824     58/pop-to-eax
 9825     # . epilogue
 9826     89/<- %esp 5/r32/ebp
 9827     5d/pop-to-ebp
 9828     c3/return
 9829 
 9830 $lookup-or-define-var:abort:
 9831     (write-buffered *(ebp+0x18) "unknown variable '")
 9832     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 9833     (write-buffered *(ebp+0x18) "'\n")
 9834     (flush *(ebp+0x18))
 9835     (stop *(ebp+0x1c) 1)
 9836     # never gets here
 9837 
 9838 find-in-function-outputs:  # fn: (addr function), name: (addr slice), out: (addr handle var)
 9839     # . prologue
 9840     55/push-ebp
 9841     89/<- %ebp 4/r32/esp
 9842     # . save registers
 9843     50/push-eax
 9844     51/push-ecx
 9845     # var curr/ecx: (addr list var) = lookup(fn->outputs)
 9846     8b/-> *(ebp+8) 1/r32/ecx
 9847     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
 9848     89/<- %ecx 0/r32/eax
 9849     # while curr != null
 9850     {
 9851       81 7/subop/compare %ecx 0/imm32
 9852       74/jump-if-= break/disp8
 9853       # var v/eax: (addr var) = lookup(curr->value)
 9854       (lookup *ecx *(ecx+4))  # List-value List-value => eax
 9855       # var s/eax: (addr array byte) = lookup(v->name)
 9856       (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9857       # if (s == name) return curr->value
 9858       (slice-equal? *(ebp+0xc) %eax)  # => eax
 9859       3d/compare-eax-and 0/imm32/false
 9860       {
 9861         74/jump-if-= break/disp8
 9862         # var edi = out
 9863         57/push-edi
 9864         8b/-> *(ebp+0x10) 7/r32/edi
 9865         # *out = curr->value
 9866         8b/-> *ecx 0/r32/eax
 9867         89/<- *edi 0/r32/eax
 9868         8b/-> *(ecx+4) 0/r32/eax
 9869         89/<- *(edi+4) 0/r32/eax
 9870         #
 9871         5f/pop-to-edi
 9872         eb/jump $find-in-function-outputs:end/disp8
 9873       }
 9874       # curr = curr->next
 9875       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
 9876       89/<- %ecx 0/r32/eax
 9877       #
 9878       eb/jump loop/disp8
 9879     }
 9880     b8/copy-to-eax 0/imm32
 9881 $find-in-function-outputs:end:
 9882     # . restore registers
 9883     59/pop-to-ecx
 9884     58/pop-to-eax
 9885     # . epilogue
 9886     89/<- %esp 5/r32/ebp
 9887     5d/pop-to-ebp
 9888     c3/return
 9889 
 9890 # push 'out' to 'vars' if not already there; it's assumed to be a fn output
 9891 maybe-define-var:  # out: (handle var), vars: (addr stack live-var)
 9892     # . prologue
 9893     55/push-ebp
 9894     89/<- %ebp 4/r32/esp
 9895     # . save registers
 9896     50/push-eax
 9897     # var out-addr/eax: (addr var)
 9898     (lookup *(ebp+8) *(ebp+0xc))  # => eax
 9899     #
 9900     (binding-exists? %eax *(ebp+0x10))  # => eax
 9901     3d/compare-eax-and 0/imm32/false
 9902     75/jump-if-!= $maybe-define-var:end/disp8
 9903     # otherwise update vars
 9904     (push *(ebp+0x10) *(ebp+8))
 9905     (push *(ebp+0x10) *(ebp+0xc))
 9906     (push *(ebp+0x10) 0)  # 'out' is always a fn output; never spill it
 9907 $maybe-define-var:end:
 9908     # . restore registers
 9909     58/pop-to-eax
 9910     # . epilogue
 9911     89/<- %esp 5/r32/ebp
 9912     5d/pop-to-ebp
 9913     c3/return
 9914 
 9915 # simpler version of lookup-var-helper
 9916 binding-exists?:  # target: (addr var), vars: (addr stack live-var) -> result/eax: boolean
 9917     # pseudocode:
 9918     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
 9919     #   var min = vars->data
 9920     #   while curr >= min
 9921     #     var v: (handle var) = *curr
 9922     #     if v->name == target->name
 9923     #       return true
 9924     #     curr -= 12
 9925     #   return false
 9926     #
 9927     # . prologue
 9928     55/push-ebp
 9929     89/<- %ebp 4/r32/esp
 9930     # . save registers
 9931     51/push-ecx
 9932     52/push-edx
 9933     56/push-esi
 9934     # var target-name/ecx: (addr array byte) = lookup(target->name)
 9935     8b/-> *(ebp+8) 0/r32/eax
 9936     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9937     89/<- %ecx 0/r32/eax
 9938     # esi = vars
 9939     8b/-> *(ebp+0xc) 6/r32/esi
 9940     # eax = vars->top
 9941     8b/-> *esi 0/r32/eax
 9942     # var min/edx: (addr handle var) = vars->data
 9943     8d/copy-address *(esi+8) 2/r32/edx
 9944     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
 9945     8d/copy-address *(esi+eax-4) 6/r32/esi  # vars + 8 + vars->type - 12
 9946     {
 9947 $binding-exists?:loop:
 9948       # if (curr < min) return
 9949       39/compare %esi 2/r32/edx
 9950       0f 82/jump-if-addr< break/disp32
 9951       # var v/eax: (addr var) = lookup(*curr)
 9952       (lookup *esi *(esi+4))  # => eax
 9953       # var vn/eax: (addr array byte) = lookup(v->name)
 9954       (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9955       # if (vn == target-name) return true
 9956       (string-equal? %ecx %eax)  # => eax
 9957       3d/compare-eax-and 0/imm32/false
 9958       75/jump-if-!= $binding-exists?:end/disp8  # eax already contains true
 9959       # curr -= 12
 9960       81 5/subop/subtract %esi 0xc/imm32
 9961       e9/jump loop/disp32
 9962     }
 9963     b8/copy-to-eax 0/imm32/false
 9964 $binding-exists?:end:
 9965     # . restore registers
 9966     5e/pop-to-esi
 9967     5a/pop-to-edx
 9968     59/pop-to-ecx
 9969     # . epilogue
 9970     89/<- %esp 5/r32/ebp
 9971     5d/pop-to-ebp
 9972     c3/return
 9973 
 9974 test-parse-mu-stmt:
 9975     # . prologue
 9976     55/push-ebp
 9977     89/<- %ebp 4/r32/esp
 9978     # setup
 9979     (clear-stream _test-input-stream)
 9980     (write _test-input-stream "increment n\n")
 9981     # var vars/ecx: (stack (addr var) 16)
 9982     81 5/subop/subtract %esp 0xc0/imm32
 9983     68/push 0xc0/imm32/size
 9984     68/push 0/imm32/top
 9985     89/<- %ecx 4/r32/esp
 9986     (clear-stack %ecx)
 9987     # var v/edx: (handle var)
 9988     68/push 0/imm32
 9989     68/push 0/imm32
 9990     89/<- %edx 4/r32/esp
 9991     # var s/eax: (handle array byte)
 9992     68/push 0/imm32
 9993     68/push 0/imm32
 9994     89/<- %eax 4/r32/esp
 9995     # v = new var("n")
 9996     (copy-array Heap "n" %eax)
 9997     (new-var Heap *eax *(eax+4) %edx)
 9998     #
 9999     (push %ecx *edx)
10000     (push %ecx *(edx+4))
10001     (push %ecx 0)
10002     # var out/eax: (handle stmt)
10003     68/push 0/imm32
10004     68/push 0/imm32
10005     89/<- %eax 4/r32/esp
10006     # convert
10007     (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
10008     # var out-addr/edx: (addr stmt) = lookup(*out)
10009     (lookup *eax *(eax+4))  # => eax
10010     89/<- %edx 0/r32/eax
10011     # out->tag
10012     (check-ints-equal *edx 1 "F - test-parse-mu-stmt/tag")  # Stmt-tag is Stmt1
10013     # out->operation
10014     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
10015     (check-strings-equal %eax "increment" "F - test-parse-mu-stmt/name")  # Stmt1-operation
10016     # out->inouts->value->name
10017     # . eax = out->inouts
10018     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
10019     # . eax = out->inouts->value
10020     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10021     # . eax = out->inouts->value->name
10022     (lookup *eax *(eax+4))  # Var-name Var-name => eax
10023     # .
10024     (check-strings-equal %eax "n" "F - test-parse-mu-stmt/inout:0")
10025     # . epilogue
10026     89/<- %esp 5/r32/ebp
10027     5d/pop-to-ebp
10028     c3/return
10029 
10030 test-parse-mu-stmt-with-comma:
10031     # . prologue
10032     55/push-ebp
10033     89/<- %ebp 4/r32/esp
10034     # setup
10035     (clear-stream _test-input-stream)
10036     (write _test-input-stream "copy-to n, 3\n")
10037     # var vars/ecx: (stack (addr var) 16)
10038     81 5/subop/subtract %esp 0xc0/imm32
10039     68/push 0xc0/imm32/size
10040     68/push 0/imm32/top
10041     89/<- %ecx 4/r32/esp
10042     (clear-stack %ecx)
10043     # var v/edx: (handle var)
10044     68/push 0/imm32
10045     68/push 0/imm32
10046     89/<- %edx 4/r32/esp
10047     # var s/eax: (handle array byte)
10048     68/push 0/imm32
10049     68/push 0/imm32
10050     89/<- %eax 4/r32/esp
10051     # v = new var("n")
10052     (copy-array Heap "n" %eax)
10053     (new-var Heap *eax *(eax+4) %edx)
10054     #
10055     (push %ecx *edx)
10056     (push %ecx *(edx+4))
10057     (push %ecx 0)
10058     # var out/eax: (handle stmt)
10059     68/push 0/imm32
10060     68/push 0/imm32
10061     89/<- %eax 4/r32/esp
10062     # convert
10063     (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
10064     # var out-addr/edx: (addr stmt) = lookup(*out)
10065     (lookup *eax *(eax+4))  # => eax
10066     89/<- %edx 0/r32/eax
10067     # out->tag
10068     (check-ints-equal *edx 1 "F - test-parse-mu-stmt-with-comma/tag")  # Stmt-tag is Stmt1
10069     # out->operation
10070     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
10071     (check-strings-equal %eax "copy-to" "F - test-parse-mu-stmt-with-comma/name")  # Stmt1-operation
10072     # out->inouts->value->name
10073     # . eax = out->inouts
10074     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
10075     # . eax = out->inouts->value
10076     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10077     # . eax = out->inouts->value->name
10078     (lookup *eax *(eax+4))  # Var-name Var-name => eax
10079     # .
10080     (check-strings-equal %eax "n" "F - test-parse-mu-stmt-with-comma/inout:0")
10081     # . epilogue
10082     89/<- %esp 5/r32/ebp
10083     5d/pop-to-ebp
10084     c3/return
10085 
10086 new-var:  # ad: (addr allocation-descriptor), name: (handle array byte), out: (addr handle var)
10087     # . prologue
10088     55/push-ebp
10089     89/<- %ebp 4/r32/esp
10090     # . save registers
10091     50/push-eax
10092     51/push-ecx
10093     # ecx = out
10094     8b/-> *(ebp+0x14) 1/r32/ecx
10095     #
10096     (allocate *(ebp+8) *Var-size %ecx)
10097     # var out-addr/eax: (addr var)
10098     (lookup *ecx *(ecx+4))  # => eax
10099     # out-addr->name = name
10100     8b/-> *(ebp+0xc) 1/r32/ecx
10101     89/<- *eax 1/r32/ecx  # Var-name
10102     8b/-> *(ebp+0x10) 1/r32/ecx
10103     89/<- *(eax+4) 1/r32/ecx  # Var-name
10104 #?     (write-buffered Stderr "var ")
10105 #?     (lookup *(ebp+0xc) *(ebp+0x10))
10106 #?     (write-buffered Stderr %eax)
10107 #?     (write-buffered Stderr " at ")
10108 #?     8b/-> *(ebp+0x14) 1/r32/ecx
10109 #?     (lookup *ecx *(ecx+4))  # => eax
10110 #?     (write-int32-hex-buffered Stderr %eax)
10111 #?     (write-buffered Stderr Newline)
10112 #?     (flush Stderr)
10113 $new-var:end:
10114     # . restore registers
10115     59/pop-to-ecx
10116     58/pop-to-eax
10117     # . epilogue
10118     89/<- %esp 5/r32/ebp
10119     5d/pop-to-ebp
10120     c3/return
10121 
10122 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)
10123     # . prologue
10124     55/push-ebp
10125     89/<- %ebp 4/r32/esp
10126     # . save registers
10127     50/push-eax
10128     51/push-ecx
10129     # if (!is-hex-int?(name)) abort
10130     (is-hex-int? *(ebp+0xc))  # => eax
10131     3d/compare-eax-and 0/imm32/false
10132     0f 84/jump-if-= $new-literal-integer:abort/disp32
10133     # a little more error-checking
10134     (check-mu-hex-int *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c))
10135     # out = new var(s)
10136     (new-var-from-slice *(ebp+8) *(ebp+0xc) *(ebp+0x10))
10137     # var out-addr/ecx: (addr var) = lookup(*out)
10138     8b/-> *(ebp+0x10) 0/r32/eax
10139     (lookup *eax *(eax+4))  # => eax
10140     89/<- %ecx 0/r32/eax
10141     # out-addr->block-depth = *Curr-block-depth
10142     8b/-> *Curr-block-depth 0/r32/eax
10143     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
10144     # out-addr->type = new tree()
10145     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
10146     (allocate *(ebp+8) *Type-tree-size %eax)
10147     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
10148     c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
10149     # nothing else to do; default type is 'literal'
10150 $new-literal-integer:end:
10151     # . reclaim locals
10152     81 0/subop/add %esp 8/imm32
10153     # . restore registers
10154     59/pop-to-ecx
10155     58/pop-to-eax
10156     # . epilogue
10157     89/<- %esp 5/r32/ebp
10158     5d/pop-to-ebp
10159     c3/return
10160 
10161 $new-literal-integer:abort:
10162     (write-buffered *(ebp+0x18) "fn ")
10163     8b/-> *(ebp+0x14) 0/r32/eax
10164     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10165     (write-buffered *(ebp+0x18) %eax)
10166     (write-buffered *(ebp+0x18) ": variable '")
10167     (write-slice-buffered *(ebp+0x18) *(ebp+0xc))
10168     (write-buffered *(ebp+0x18) "' cannot begin with a digit (or do you have a typo in a number?)\n")
10169     (flush *(ebp+0x18))
10170     (stop *(ebp+0x1c) 1)
10171     # never gets here
10172 
10173 # precondition: name is a valid hex integer; require a '0x' prefix
10174 check-mu-hex-int:  # name: (addr slice), err: (addr buffered-file), ed: (addr exit-descriptor)
10175     # . prologue
10176     55/push-ebp
10177     89/<- %ebp 4/r32/esp
10178     # . save registers
10179     50/push-eax
10180     51/push-ecx
10181     52/push-edx
10182     #
10183     8b/-> *(ebp+8) 1/r32/ecx
10184     # var start/ecx: (addr byte) = name->start
10185     8b/-> *(ecx+4) 2/r32/edx
10186     # var end/ecx: (addr byte) = name->end
10187     8b/-> *ecx 1/r32/ecx
10188     # var len/eax: int = name->end - name->start
10189     89/<- %eax 2/r32/edx
10190     29/subtract-from %eax 1/r32/ecx
10191     # if (len <= 1) return
10192     3d/compare-eax-with 1/imm32
10193     0f 8e/jump-if-<= $check-mu-hex-int:end/disp32
10194 $check-mu-hex-int:length->-1:
10195     # if slice-starts-with?("0x") return
10196     (slice-starts-with? *(ebp+8) "0x")  # => eax
10197     3d/compare-eax-with 0/imm32/false
10198     75/jump-if-!= $check-mu-hex-int:end/disp8
10199 $check-mu-hex-int:abort:
10200     # otherwise abort
10201     (write-buffered *(ebp+0xc) "literal integers are always hex in Mu; either start '")
10202     (write-slice-buffered *(ebp+0xc) *(ebp+8))
10203     (write-buffered *(ebp+0xc) "' with a '0x' to be unambiguous, or convert it to decimal.\n")
10204     (flush *(ebp+0xc))
10205     (stop *(ebp+0x10) 1)
10206 $check-mu-hex-int:end:
10207     # . restore registers
10208     5a/pop-to-edx
10209     59/pop-to-ecx
10210     58/pop-to-eax
10211     # . epilogue
10212     89/<- %esp 5/r32/ebp
10213     5d/pop-to-ebp
10214     c3/return
10215 
10216 new-literal:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
10217     # . prologue
10218     55/push-ebp
10219     89/<- %ebp 4/r32/esp
10220     # . save registers
10221     50/push-eax
10222     51/push-ecx
10223     # var s/ecx: (handle array byte)
10224     68/push 0/imm32
10225     68/push 0/imm32
10226     89/<- %ecx 4/r32/esp
10227     # s = slice-to-string(name)
10228     (slice-to-string Heap *(ebp+0xc) %ecx)
10229     # allocate to out
10230     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
10231     # var out-addr/ecx: (addr var) = lookup(*out)
10232     8b/-> *(ebp+0x10) 1/r32/ecx
10233     (lookup *ecx *(ecx+4))  # => eax
10234     89/<- %ecx 0/r32/eax
10235     # out-addr->block-depth = *Curr-block-depth
10236     8b/-> *Curr-block-depth 0/r32/eax
10237     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
10238     # out-addr->type/eax = new type
10239     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
10240     (allocate *(ebp+8) *Type-tree-size %eax)
10241     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
10242     # nothing else to do; default type is 'literal'
10243     c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
10244 $new-literal:end:
10245     # . reclaim locals
10246     81 0/subop/add %esp 8/imm32
10247     # . restore registers
10248     59/pop-to-ecx
10249     58/pop-to-eax
10250     # . epilogue
10251     89/<- %esp 5/r32/ebp
10252     5d/pop-to-ebp
10253     c3/return
10254 
10255 new-var-from-slice:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
10256     # . prologue
10257     55/push-ebp
10258     89/<- %ebp 4/r32/esp
10259     # . save registers
10260     51/push-ecx
10261     # var tmp/ecx: (handle array byte)
10262     68/push 0/imm32
10263     68/push 0/imm32
10264     89/<- %ecx 4/r32/esp
10265     # tmp = slice-to-string(name)
10266     (slice-to-string Heap *(ebp+0xc) %ecx)
10267     # out = new-var(tmp)
10268     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
10269 $new-var-from-slice:end:
10270     # . reclaim locals
10271     81 0/subop/add %esp 8/imm32
10272     # . restore registers
10273     59/pop-to-ecx
10274     # . epilogue
10275     89/<- %esp 5/r32/ebp
10276     5d/pop-to-ebp
10277     c3/return
10278 
10279 new-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
10280     # . prologue
10281     55/push-ebp
10282     89/<- %ebp 4/r32/esp
10283     # . save registers
10284     50/push-eax
10285     51/push-ecx
10286     #
10287     (allocate *(ebp+8) *Stmt-size *(ebp+0x14))
10288     # var out-addr/eax: (addr stmt) = lookup(*out)
10289     8b/-> *(ebp+0x14) 0/r32/eax
10290     (lookup *eax *(eax+4))  # => eax
10291     # out-addr->tag = stmt
10292     c7 0/subop/copy *eax 2/imm32/tag/var-on-stack  # Stmt-tag
10293     # result->var = var
10294     8b/-> *(ebp+0xc) 1/r32/ecx
10295     89/<- *(eax+4) 1/r32/ecx  # Vardef-var
10296     8b/-> *(ebp+0x10) 1/r32/ecx
10297     89/<- *(eax+8) 1/r32/ecx  # Vardef-var
10298 $new-var-def:end:
10299     # . restore registers
10300     59/pop-to-ecx
10301     58/pop-to-eax
10302     # . epilogue
10303     89/<- %esp 5/r32/ebp
10304     5d/pop-to-ebp
10305     c3/return
10306 
10307 new-reg-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
10308     # . prologue
10309     55/push-ebp
10310     89/<- %ebp 4/r32/esp
10311     # . save registers
10312     50/push-eax
10313     # eax = out
10314     8b/-> *(ebp+0x14) 0/r32/eax
10315     #
10316     (allocate *(ebp+8) *Stmt-size %eax)
10317     # var out-addr/eax: (addr stmt) = lookup(*out)
10318     (lookup *eax *(eax+4))  # => eax
10319     # set tag
10320     c7 0/subop/copy *eax 3/imm32/tag/var-in-register  # Stmt-tag
10321     # set output
10322     8d/copy-address *(eax+0x14) 0/r32/eax  # Regvardef-outputs
10323     (append-stmt-var Heap  *(ebp+0xc) *(ebp+0x10)  0 0  0  %eax)
10324 $new-reg-var-def:end:
10325     # . restore registers
10326     58/pop-to-eax
10327     # . epilogue
10328     89/<- %esp 5/r32/ebp
10329     5d/pop-to-ebp
10330     c3/return
10331 
10332 append-list:  # ad: (addr allocation-descriptor), value: (handle _type), list: (handle list _type), out: (addr handle list _type)
10333     # . prologue
10334     55/push-ebp
10335     89/<- %ebp 4/r32/esp
10336     # . save registers
10337     50/push-eax
10338     51/push-ecx
10339     57/push-edi
10340     # edi = out
10341     8b/-> *(ebp+0x1c) 7/r32/edi
10342     # *out = new list
10343     (allocate *(ebp+8) *List-size %edi)
10344     # var out-addr/edi: (addr list _type) = lookup(*out)
10345     (lookup *edi *(edi+4))  # => eax
10346     89/<- %edi 0/r32/eax
10347     # out-addr->value = value
10348     8b/-> *(ebp+0xc) 0/r32/eax
10349     89/<- *edi 0/r32/eax  # List-value
10350     8b/-> *(ebp+0x10) 0/r32/eax
10351     89/<- *(edi+4) 0/r32/eax  # List-value
10352     # if (list == null) return
10353     81 7/subop/compare *(ebp+0x14) 0/imm32
10354     74/jump-if-= $append-list:end/disp8
10355     # otherwise append
10356 $append-list:non-empty-list:
10357     # var curr/eax: (addr list _type) = lookup(list)
10358     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
10359     # while (curr->next != null) curr = curr->next
10360     {
10361       81 7/subop/compare *(eax+8) 0/imm32  # List-next
10362       74/jump-if-= break/disp8
10363       # curr = lookup(curr->next)
10364       (lookup *(eax+8) *(eax+0xc))  # List-next, List-next => eax
10365       #
10366       eb/jump loop/disp8
10367     }
10368     # edi = out
10369     8b/-> *(ebp+0x1c) 7/r32/edi
10370     # curr->next = out
10371     8b/-> *edi 1/r32/ecx
10372     89/<- *(eax+8) 1/r32/ecx  # List-next
10373     8b/-> *(edi+4) 1/r32/ecx
10374     89/<- *(eax+0xc) 1/r32/ecx  # List-next
10375     # out = list
10376     8b/-> *(ebp+0x14) 1/r32/ecx
10377     89/<- *edi 1/r32/ecx
10378     8b/-> *(ebp+0x18) 1/r32/ecx
10379     89/<- *(edi+4) 1/r32/ecx
10380 $append-list:end:
10381     # . restore registers
10382     5f/pop-to-edi
10383     59/pop-to-ecx
10384     58/pop-to-eax
10385     # . epilogue
10386     89/<- %esp 5/r32/ebp
10387     5d/pop-to-ebp
10388     c3/return
10389 
10390 append-stmt-var:  # ad: (addr allocation-descriptor), v: (handle var), vars: (handle stmt-var), is-deref?: boolean, out: (addr handle stmt-var)
10391     # . prologue
10392     55/push-ebp
10393     89/<- %ebp 4/r32/esp
10394     # . save registers
10395     50/push-eax
10396     51/push-ecx
10397     57/push-edi
10398     # edi = out
10399     8b/-> *(ebp+0x20) 7/r32/edi
10400     # out = new stmt-var
10401     (allocate *(ebp+8) *Stmt-var-size %edi)
10402     # var out-addr/ecx: (addr stmt-var) = lookup(*out)
10403     (lookup *edi *(edi+4))  # => eax
10404     89/<- %ecx 0/r32/eax
10405     # out-addr->value = v
10406     8b/-> *(ebp+0xc) 0/r32/eax
10407     89/<- *ecx 0/r32/eax  # Stmt-var-value
10408     8b/-> *(ebp+0x10) 0/r32/eax
10409     89/<- *(ecx+4) 0/r32/eax  # Stmt-var-value
10410     # out-addr->is-deref? = is-deref?
10411     8b/-> *(ebp+0x1c) 0/r32/eax
10412     89/<- *(ecx+0x10) 0/r32/eax  # Stmt-var-is-deref
10413     # if (vars == null) return result
10414     81 7/subop/compare *(ebp+0x14) 0/imm32/null
10415     74/jump-if-= $append-stmt-var:end/disp8
10416     # otherwise append
10417     # var curr/eax: (addr stmt-var) = lookup(vars)
10418     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
10419     # while (curr->next != null) curr = curr->next
10420     {
10421       81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
10422       74/jump-if-= break/disp8
10423       # curr = lookup(curr->next)
10424       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next, Stmt-var-next => eax
10425       #
10426       eb/jump loop/disp8
10427     }
10428     # curr->next = out
10429     8b/-> *edi 1/r32/ecx
10430     89/<- *(eax+8) 1/r32/ecx  # Stmt-var-next
10431     8b/-> *(edi+4) 1/r32/ecx
10432     89/<- *(eax+0xc) 1/r32/ecx  # Stmt-var-next
10433     # out = vars
10434     8b/-> *(ebp+0x14) 1/r32/ecx
10435     89/<- *edi 1/r32/ecx
10436     8b/-> *(ebp+0x18) 1/r32/ecx
10437     89/<- *(edi+4) 1/r32/ecx
10438 $append-stmt-var:end:
10439     # . restore registers
10440     5f/pop-to-edi
10441     59/pop-to-ecx
10442     58/pop-to-eax
10443     # . epilogue
10444     89/<- %esp 5/r32/ebp
10445     5d/pop-to-ebp
10446     c3/return
10447 
10448 append-to-block:  # ad: (addr allocation-descriptor), block: (addr block), x: (handle stmt)
10449     # . prologue
10450     55/push-ebp
10451     89/<- %ebp 4/r32/esp
10452     # . save registers
10453     50/push-eax
10454     56/push-esi
10455     # esi = block
10456     8b/-> *(ebp+0xc) 6/r32/esi
10457     # block->stmts = append(x, block->stmts)
10458     8d/copy-address *(esi+4) 0/r32/eax  # Block-stmts
10459     (append-list *(ebp+8)  *(ebp+0x10) *(ebp+0x14)  *(esi+4) *(esi+8)  %eax)  # ad, x, x, Block-stmts, Block-stmts
10460 $append-to-block:end:
10461     # . restore registers
10462     5e/pop-to-esi
10463     58/pop-to-eax
10464     # . epilogue
10465     89/<- %esp 5/r32/ebp
10466     5d/pop-to-ebp
10467     c3/return
10468 
10469 ## Parsing types
10470 # We need to create metadata on user-defined types, and we need to use this
10471 # metadata as we parse instructions.
10472 # However, we also want to allow types to be used before their definitions.
10473 # This means we can't ever assume any type data structures exist.
10474 
10475 lookup-or-create-constant:  # container: (addr stmt-var), field-name: (addr slice), out: (addr handle var)
10476     # . prologue
10477     55/push-ebp
10478     89/<- %ebp 4/r32/esp
10479     # . save registers
10480     50/push-eax
10481     56/push-esi
10482     # var container-type/esi: type-id
10483     (container-type *(ebp+8))  # => eax
10484     89/<- %esi 0/r32/eax
10485     # var tmp/eax: (handle typeinfo) = find-or-create-typeinfo(container-type)
10486     68/push 0/imm32
10487     68/push 0/imm32
10488     89/<- %eax 4/r32/esp
10489     (find-or-create-typeinfo %esi %eax)
10490     # var tmp-addr/eax: (addr typeinfo) = lookup(tmp)
10491     (lookup *eax *(eax+4))  # => eax
10492     # result = find-or-create-typeinfo-output-var(typeinfo, field-name)
10493 #?     (write-buffered Stderr "constant: ")
10494 #?     (write-slice-buffered Stderr *(ebp+0xc))
10495 #?     (write-buffered Stderr Newline)
10496 #?     (flush Stderr)
10497     (find-or-create-typeinfo-output-var %eax *(ebp+0xc) *(ebp+0x10))
10498 #?     8b/-> *(ebp+0x10) 0/r32/eax
10499 #?     (write-buffered Stderr "@")
10500 #?     (lookup *eax *(eax+4))
10501 #?     (write-int32-hex-buffered Stderr %eax)
10502 #?     (lookup *eax *(eax+4))
10503 #?     (write-buffered Stderr %eax)
10504 #?     (write-buffered Stderr Newline)
10505 #?     (flush Stderr)
10506 #?     (write-buffered Stderr "offset: ")
10507 #?     8b/-> *(eax+0x14) 0/r32/eax
10508 #?     (write-int32-hex-buffered Stderr %eax)
10509 #?     (write-buffered Stderr Newline)
10510 #?     (flush Stderr)
10511 $lookup-or-create-constant:end:
10512     # . reclaim locals
10513     81 0/subop/add %esp 8/imm32
10514     # . restore registers
10515     5e/pop-to-esi
10516     58/pop-to-eax
10517     # . epilogue
10518     89/<- %esp 5/r32/ebp
10519     5d/pop-to-ebp
10520     c3/return
10521 
10522 # if addr var:
10523 #   container->var->type->right->left->value
10524 # otherwise
10525 #   container->var->type->value
10526 container-type:  # container: (addr stmt-var) -> result/eax: type-id
10527     # . prologue
10528     55/push-ebp
10529     89/<- %ebp 4/r32/esp
10530     #
10531     8b/-> *(ebp+8) 0/r32/eax
10532     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10533     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
10534     {
10535       81 7/subop/compare *(eax+8) 0/imm32  # Type-tree-right
10536       74/jump-if-= break/disp8
10537       (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
10538       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
10539     }
10540     8b/-> *(eax+4) 0/r32/eax  # Type-tree-value
10541 $container-type:end:
10542     # . epilogue
10543     89/<- %esp 5/r32/ebp
10544     5d/pop-to-ebp
10545     c3/return
10546 
10547 is-container?:  # t: type-id -> result/eax: boolean
10548     # . prologue
10549     55/push-ebp
10550     89/<- %ebp 4/r32/esp
10551     #
10552     8b/-> *(ebp+8) 0/r32/eax
10553     c1/shift 4/subop/left %eax 2/imm8
10554     3b/compare 0/r32/eax *Primitive-type-ids
10555     0f 9d/set-if->= %al
10556     81 4/subop/and %eax 0xff/imm32
10557 $is-container?:end:
10558     # . epilogue
10559     89/<- %esp 5/r32/ebp
10560     5d/pop-to-ebp
10561     c3/return
10562 
10563 find-or-create-typeinfo:  # t: type-id, out: (addr handle typeinfo)
10564     # . prologue
10565     55/push-ebp
10566     89/<- %ebp 4/r32/esp
10567     # . save registers
10568     50/push-eax
10569     51/push-ecx
10570     52/push-edx
10571     57/push-edi
10572     # edi = out
10573     8b/-> *(ebp+0xc) 7/r32/edi
10574     # var fields/ecx: (handle table (handle array byte) (handle typeinfo-entry))
10575     68/push 0/imm32
10576     68/push 0/imm32
10577     89/<- %ecx 4/r32/esp
10578     # find-typeinfo(t, out)
10579     (find-typeinfo *(ebp+8) %edi)
10580     {
10581       # if (*out != 0) break
10582       81 7/subop/compare *edi 0/imm32
10583       0f 85/jump-if-!= break/disp32
10584 $find-or-create-typeinfo:create:
10585       # *out = allocate
10586       (allocate Heap *Typeinfo-size %edi)
10587       # var tmp/eax: (addr typeinfo) = lookup(*out)
10588       (lookup *edi *(edi+4))  # => eax
10589 #?     (write-buffered Stderr "created typeinfo at ")
10590 #?     (write-int32-hex-buffered Stderr %eax)
10591 #?     (write-buffered Stderr " for type-id ")
10592 #?     (write-int32-hex-buffered Stderr *(ebp+8))
10593 #?     (write-buffered Stderr Newline)
10594 #?     (flush Stderr)
10595       # tmp->id = t
10596       8b/-> *(ebp+8) 2/r32/edx
10597       89/<- *eax 2/r32/edx  # Typeinfo-id
10598       # tmp->fields = new table
10599       # . fields = new table
10600       (new-stream Heap 0x40 *Typeinfo-fields-row-size %ecx)
10601       # . tmp->fields = fields
10602       8b/-> *ecx 2/r32/edx
10603       89/<- *(eax+4) 2/r32/edx  # Typeinfo-fields
10604       8b/-> *(ecx+4) 2/r32/edx
10605       89/<- *(eax+8) 2/r32/edx  # Typeinfo-fields
10606       # tmp->next = Program->types
10607       8b/-> *_Program-types 1/r32/ecx
10608       89/<- *(eax+0x10) 1/r32/ecx  # Typeinfo-next
10609       8b/-> *_Program-types->payload 1/r32/ecx
10610       89/<- *(eax+0x14) 1/r32/ecx  # Typeinfo-next
10611       # Program->types = out
10612       8b/-> *edi 1/r32/ecx
10613       89/<- *_Program-types 1/r32/ecx
10614       8b/-> *(edi+4) 1/r32/ecx
10615       89/<- *_Program-types->payload 1/r32/ecx
10616     }
10617 $find-or-create-typeinfo:end:
10618     # . reclaim locals
10619     81 0/subop/add %esp 8/imm32
10620     # . restore registers
10621     5f/pop-to-edi
10622     5a/pop-to-edx
10623     59/pop-to-ecx
10624     58/pop-to-eax
10625     # . epilogue
10626     89/<- %esp 5/r32/ebp
10627     5d/pop-to-ebp
10628     c3/return
10629 
10630 find-typeinfo:  # t: type-id, out: (addr handle typeinfo)
10631     # . prologue
10632     55/push-ebp
10633     89/<- %ebp 4/r32/esp
10634     # . save registers
10635     50/push-eax
10636     51/push-ecx
10637     52/push-edx
10638     57/push-edi
10639     # ecx = t
10640     8b/-> *(ebp+8) 1/r32/ecx
10641     # edi = out
10642     8b/-> *(ebp+0xc) 7/r32/edi
10643     # *out = Program->types
10644     8b/-> *_Program-types 0/r32/eax
10645     89/<- *edi 0/r32/eax
10646     8b/-> *_Program-types->payload 0/r32/eax
10647     89/<- *(edi+4) 0/r32/eax
10648     {
10649 $find-typeinfo:loop:
10650       # if (*out == 0) break
10651       81 7/subop/compare *edi 0/imm32
10652       74/jump-if-= break/disp8
10653 $find-typeinfo:check:
10654       # var tmp/eax: (addr typeinfo) = lookup(*out)
10655       (lookup *edi *(edi+4))  # => eax
10656       # if (tmp->id == t) break
10657       39/compare *eax 1/r32/ecx  # Typeinfo-id
10658       74/jump-if-= break/disp8
10659 $find-typeinfo:continue:
10660       # *out = tmp->next
10661       8b/-> *(eax+0x10) 2/r32/edx  # Typeinfo-next
10662       89/<- *edi 2/r32/edx
10663       8b/-> *(eax+0x14) 2/r32/edx  # Typeinfo-next
10664       89/<- *(edi+4) 2/r32/edx
10665       #
10666       eb/jump loop/disp8
10667     }
10668 $find-typeinfo:end:
10669     # . restore registers
10670     5f/pop-to-edi
10671     5a/pop-to-edx
10672     59/pop-to-ecx
10673     58/pop-to-eax
10674     # . epilogue
10675     89/<- %esp 5/r32/ebp
10676     5d/pop-to-ebp
10677     c3/return
10678 
10679 find-or-create-typeinfo-output-var:  # T: (addr typeinfo), f: (addr slice), out: (addr handle var)
10680     # . prologue
10681     55/push-ebp
10682     89/<- %ebp 4/r32/esp
10683     # . save registers
10684     50/push-eax
10685     52/push-edx
10686     57/push-edi
10687     # var dest/edi: (handle typeinfo-entry)
10688     68/push 0/imm32
10689     68/push 0/imm32
10690     89/<- %edi 4/r32/esp
10691     # find-or-create-typeinfo-fields(T, f, dest)
10692     (find-or-create-typeinfo-fields *(ebp+8) *(ebp+0xc) %edi)
10693     # var dest-addr/edi: (addr typeinfo-entry) = lookup(dest)
10694     (lookup *edi *(edi+4))  # => eax
10695     89/<- %edi 0/r32/eax
10696     # if dest-addr->output-var doesn't exist, create it
10697     {
10698       81 7/subop/compare *(edi+0xc) 0/imm32  # Typeinfo-entry-output-var
10699       0f 85/jump-if-!= break/disp32
10700       # dest-addr->output-var = new var(dummy name, type, -1 offset)
10701       # . var name/eax: (handle array byte) = "field"
10702       68/push 0/imm32
10703       68/push 0/imm32
10704       89/<- %eax 4/r32/esp
10705       (slice-to-string Heap *(ebp+0xc) %eax)
10706       # . new var
10707       8d/copy-address *(edi+0xc) 2/r32/edx
10708       (new-var Heap  *eax *(eax+4)  %edx)
10709       # . reclaim name
10710       81 0/subop/add %esp 8/imm32
10711       # var result/edx: (addr var) = lookup(dest-addr->output-var)
10712       (lookup *(edi+0xc) *(edi+0x10))  # => eax
10713       89/<- %edx 0/r32/eax
10714       # result->type = new constant type
10715       8d/copy-address *(edx+8) 0/r32/eax  # Var-type
10716       (allocate Heap *Type-tree-size %eax)
10717       (lookup *(edx+8) *(edx+0xc))  # => eax
10718       c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
10719       c7 0/subop/copy *(eax+4) 6/imm32/constant  # Type-tree-value
10720       c7 0/subop/copy *(eax+8) 0/imm32  # Type-tree-left
10721       c7 0/subop/copy *(eax+0xc) 0/imm32  # Type-tree-right
10722       c7 0/subop/copy *(eax+0x10) 0/imm32  # Type-tree-right
10723       # result->offset isn't filled out yet
10724       c7 0/subop/copy *(edx+0x14) -1/imm32/uninitialized  # Var-offset
10725     }
10726     # out = dest-addr->output-var
10727     8b/-> *(ebp+0x10) 2/r32/edx
10728     8b/-> *(edi+0xc) 0/r32/eax  # Typeinfo-entry-output-var
10729     89/<- *edx 0/r32/eax
10730     8b/-> *(edi+0x10) 0/r32/eax  # Typeinfo-entry-output-var
10731     89/<- *(edx+4) 0/r32/eax
10732 $find-or-create-typeinfo-output-var:end:
10733     # . reclaim locals
10734     81 0/subop/add %esp 8/imm32
10735     # . restore registers
10736     5f/pop-to-edi
10737     5a/pop-to-edx
10738     58/pop-to-eax
10739     # . epilogue
10740     89/<- %esp 5/r32/ebp
10741     5d/pop-to-ebp
10742     c3/return
10743 
10744 find-or-create-typeinfo-fields:  # T: (addr typeinfo), f: (addr slice), out: (addr handle typeinfo-entry)
10745     # . prologue
10746     55/push-ebp
10747     89/<- %ebp 4/r32/esp
10748     # . save registers
10749     50/push-eax
10750     56/push-esi
10751     57/push-edi
10752     # eax = lookup(T->fields)
10753     8b/-> *(ebp+8) 0/r32/eax
10754     (lookup *(eax+4) *(eax+8))  # Typeinfo-fields Typeinfo-fields => eax
10755     # edi = out
10756     8b/-> *(ebp+0x10) 7/r32/edi
10757     # var src/esi: (addr handle typeinfo-entry) = get-or-insert-slice(T->fields, f)
10758     (get-or-insert-slice %eax *(ebp+0xc) *Typeinfo-fields-row-size Heap)  # => eax
10759     89/<- %esi 0/r32/eax
10760     # if src doesn't exist, allocate it
10761     {
10762       81 7/subop/compare *esi 0/imm32
10763       75/jump-if-!= break/disp8
10764       (allocate Heap *Typeinfo-entry-size %esi)
10765 #?       (write-buffered Stderr "handle at ")
10766 #?       (write-int32-hex-buffered Stderr %esi)
10767 #?       (write-buffered Stderr ": ")
10768 #?       (write-int32-hex-buffered Stderr *esi)
10769 #?       (write-buffered Stderr " ")
10770 #?       (write-int32-hex-buffered Stderr *(esi+4))
10771 #?       (write-buffered Stderr Newline)
10772 #?       (flush Stderr)
10773 #?       (lookup *esi *(esi+4))
10774 #?       (write-buffered Stderr "created typeinfo fields at ")
10775 #?       (write-int32-hex-buffered Stderr %esi)
10776 #?       (write-buffered Stderr " for ")
10777 #?       (write-int32-hex-buffered Stderr *(ebp+8))
10778 #?       (write-buffered Stderr Newline)
10779 #?       (flush Stderr)
10780     }
10781     # *out = src
10782     # . *edi = *src
10783     8b/-> *esi 0/r32/eax
10784     89/<- *edi 0/r32/eax
10785     8b/-> *(esi+4) 0/r32/eax
10786     89/<- *(edi+4) 0/r32/eax
10787 $find-or-create-typeinfo-fields:end:
10788     # . restore registers
10789     5f/pop-to-edi
10790     5e/pop-to-esi
10791     58/pop-to-eax
10792     # . epilogue
10793     89/<- %esp 5/r32/ebp
10794     5d/pop-to-ebp
10795     c3/return
10796 
10797 populate-mu-type:  # in: (addr stream byte), t: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
10798     # pseudocode:
10799     #   var line: (stream byte 512)
10800     #   curr-index = 0
10801     #   while true
10802     #     clear-stream(line)
10803     #     read-line-buffered(in, line)
10804     #     if line->write == 0
10805     #       abort
10806     #     word-slice = next-mu-token(line)
10807     #     if slice-empty?(word-slice)               # end of line
10808     #       continue
10809     #     if slice-equal?(word-slice, "}")
10810     #       break
10811     #     var v: (handle var) = parse-var-with-type(word-slice, line)
10812     #     var r: (handle typeinfo-fields) = find-or-create-typeinfo-fields(t, word-slice/v->name)
10813     #     TODO: ensure that r->first is null
10814     #     r->index = curr-index
10815     #     curr-index++
10816     #     r->input-var = v
10817     #     if r->output-var == 0
10818     #       r->output-var = new literal
10819     #     TODO: ensure nothing else in line
10820     # t->total-size-in-bytes = -2 (not yet initialized)
10821     #
10822     # . prologue
10823     55/push-ebp
10824     89/<- %ebp 4/r32/esp
10825     # var curr-index: int at *(ebp-4)
10826     68/push 0/imm32
10827     # . save registers
10828     50/push-eax
10829     51/push-ecx
10830     52/push-edx
10831     53/push-ebx
10832     56/push-esi
10833     57/push-edi
10834     # edi = t
10835     8b/-> *(ebp+0xc) 7/r32/edi
10836     # var line/ecx: (stream byte 512)
10837     81 5/subop/subtract %esp 0x200/imm32
10838     68/push 0x200/imm32/size
10839     68/push 0/imm32/read
10840     68/push 0/imm32/write
10841     89/<- %ecx 4/r32/esp
10842     # var word-slice/edx: slice
10843     68/push 0/imm32/end
10844     68/push 0/imm32/start
10845     89/<- %edx 4/r32/esp
10846     # var v/esi: (handle var)
10847     68/push 0/imm32
10848     68/push 0/imm32
10849     89/<- %esi 4/r32/esp
10850     # var r/ebx: (handle typeinfo-entry)
10851     68/push 0/imm32
10852     68/push 0/imm32
10853     89/<- %ebx 4/r32/esp
10854     {
10855 $populate-mu-type:line-loop:
10856       (clear-stream %ecx)
10857       (read-line-buffered *(ebp+8) %ecx)
10858       # if (line->write == 0) abort
10859       81 7/subop/compare *ecx 0/imm32
10860       0f 84/jump-if-= $populate-mu-type:error1/disp32
10861 +--  6 lines: #?       # dump line ------------------------------------------------------------------------------------------------------------------------------------------------------
10867       (next-mu-token %ecx %edx)
10868       # if slice-empty?(word-slice) continue
10869       (slice-empty? %edx)  # => eax
10870       3d/compare-eax-and 0/imm32
10871       0f 85/jump-if-!= loop/disp32
10872       # if slice-equal?(word-slice, "}") break
10873       (slice-equal? %edx "}")
10874       3d/compare-eax-and 0/imm32
10875       0f 85/jump-if-!= break/disp32
10876 $populate-mu-type:parse-element:
10877       # v = parse-var-with-type(word-slice, first-line)
10878       # must do this first to strip the trailing ':' from word-slice before
10879       # using it in find-or-create-typeinfo-fields below
10880       # TODO: clean up that mutation in parse-var-with-type
10881       (parse-var-with-type %edx %ecx %esi *(ebp+0x10) *(ebp+0x14))
10882       # if v is an addr, abort
10883       (lookup *esi *(esi+4))  # => eax
10884       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
10885       (is-mu-addr-type? %eax)  # => eax
10886       3d/compare-eax-and 0/imm32/false
10887       0f 85/jump-if-!= $populate-mu-type:error2/disp32
10888       # if v is an array, abort  (we could support it, but initialization gets complex)
10889       (lookup *esi *(esi+4))  # => eax
10890       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
10891       (is-mu-array-type? %eax)  # => eax
10892       3d/compare-eax-and 0/imm32/false
10893       0f 85/jump-if-!= $populate-mu-type:error3/disp32
10894       # if v is a byte, abort
10895       (lookup *esi *(esi+4))  # => eax
10896       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
10897       (is-simple-mu-type? %eax 8)  # byte => eax
10898       3d/compare-eax-and 0/imm32/false
10899       0f 85/jump-if-!= $populate-mu-type:error4/disp32
10900       # if v is a slice, abort
10901       (lookup *esi *(esi+4))  # => eax
10902       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
10903       (is-simple-mu-type? %eax 0xc)  # slice => eax
10904       3d/compare-eax-and 0/imm32/false
10905       0f 85/jump-if-!= $populate-mu-type:error5/disp32
10906       # if v is a stream, abort  (we could support it, but initialization gets even more complex)
10907       (lookup *esi *(esi+4))  # => eax
10908       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
10909       (is-mu-stream-type? %eax)  # => eax
10910       3d/compare-eax-and 0/imm32/false
10911       0f 85/jump-if-!= $populate-mu-type:error6/disp32
10912       # var tmp/ecx
10913       51/push-ecx
10914 $populate-mu-type:create-typeinfo-fields:
10915       # var r/ebx: (handle typeinfo-entry)
10916       (find-or-create-typeinfo-fields %edi %edx %ebx)
10917       # r->index = curr-index
10918       (lookup *ebx *(ebx+4))  # => eax
10919       8b/-> *(ebp-4) 1/r32/ecx
10920 #?       (write-buffered Stderr "saving index ")
10921 #?       (write-int32-hex-buffered Stderr %ecx)
10922 #?       (write-buffered Stderr " at ")
10923 #?       (write-int32-hex-buffered Stderr %edi)
10924 #?       (write-buffered Stderr Newline)
10925 #?       (flush Stderr)
10926       89/<- *(eax+8) 1/r32/ecx  # Typeinfo-entry-index
10927       # ++curr-index
10928       ff 0/subop/increment *(ebp-4)
10929 $populate-mu-type:set-input-type:
10930       # r->input-var = v
10931       8b/-> *esi 1/r32/ecx
10932       89/<- *eax 1/r32/ecx  # Typeinfo-entry-input-var
10933       8b/-> *(esi+4) 1/r32/ecx
10934       89/<- *(eax+4) 1/r32/ecx  # Typeinfo-entry-input-var
10935       # restore line
10936       59/pop-to-ecx
10937       {
10938 $populate-mu-type:create-output-type:
10939         # if (r->output-var == 0) create a new var with some placeholder data
10940         81 7/subop/compare *(eax+0xc) 0/imm32  # Typeinfo-entry-output-var
10941         75/jump-if-!= break/disp8
10942         8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
10943         (new-literal Heap %edx %eax)
10944       }
10945       e9/jump loop/disp32
10946     }
10947 $populate-mu-type:invalidate-total-size-in-bytes:
10948     # Offsets and total size may not be accurate here since we may not yet
10949     # have encountered the element types.
10950     # We'll recompute them separately after parsing the entire program.
10951     c7 0/subop/copy *(edi+0xc) -2/imm32/uninitialized  # Typeinfo-total-size-in-bytes
10952 $populate-mu-type:end:
10953     # . reclaim locals
10954     81 0/subop/add %esp 0x224/imm32
10955     # . restore registers
10956     5f/pop-to-edi
10957     5e/pop-to-esi
10958     5b/pop-to-ebx
10959     5a/pop-to-edx
10960     59/pop-to-ecx
10961     58/pop-to-eax
10962     # reclaim curr-index
10963     81 0/subop/add %esp 4/imm32
10964     # . epilogue
10965     89/<- %esp 5/r32/ebp
10966     5d/pop-to-ebp
10967     c3/return
10968 
10969 $populate-mu-type:error1:
10970     # error("incomplete type definition '" t->name "'\n")
10971     (write-buffered *(ebp+0x10) "incomplete type definition '")
10972     (type-name *edi)  # Typeinfo-id => eax
10973     (write-buffered *(ebp+0x10) %eax)
10974     (write-buffered *(ebp+0x10) "\n")
10975     (flush *(ebp+0x10))
10976     (stop *(ebp+0x14) 1)
10977     # never gets here
10978 
10979 $populate-mu-type:error2:
10980     (write-buffered *(ebp+0x10) "type ")
10981     (type-name *edi)  # Typeinfo-id => eax
10982     (write-buffered *(ebp+0x10) %eax)
10983     (write-buffered *(ebp+0x10) ": 'addr' elements not allowed\n")
10984     (flush *(ebp+0x10))
10985     (stop *(ebp+0x14) 1)
10986     # never gets here
10987 
10988 $populate-mu-type:error3:
10989     (write-buffered *(ebp+0x10) "type ")
10990     (type-name *edi)  # Typeinfo-id => eax
10991     (write-buffered *(ebp+0x10) %eax)
10992     (write-buffered *(ebp+0x10) ": 'array' elements not allowed for now\n")
10993     (flush *(ebp+0x10))
10994     (stop *(ebp+0x14) 1)
10995     # never gets here
10996 
10997 $populate-mu-type:error4:
10998     (write-buffered *(ebp+0x10) "type ")
10999     (type-name *edi)  # Typeinfo-id => eax
11000     (write-buffered *(ebp+0x10) %eax)
11001     (write-buffered *(ebp+0x10) ": 'byte' elements not allowed\n")
11002     (flush *(ebp+0x10))
11003     (stop *(ebp+0x14) 1)
11004     # never gets here
11005 
11006 $populate-mu-type:error5:
11007     (write-buffered *(ebp+0x10) "type ")
11008     (type-name *edi)  # Typeinfo-id => eax
11009     (write-buffered *(ebp+0x10) %eax)
11010     (write-buffered *(ebp+0x10) ": 'slice' elements not allowed\n")
11011     (flush *(ebp+0x10))
11012     (stop *(ebp+0x14) 1)
11013     # never gets here
11014 
11015 $populate-mu-type:error6:
11016     (write-buffered *(ebp+0x10) "type ")
11017     (type-name *edi)  # Typeinfo-id => eax
11018     (write-buffered *(ebp+0x10) %eax)
11019     (write-buffered *(ebp+0x10) ": 'stream' elements not allowed for now\n")
11020     (flush *(ebp+0x10))
11021     (stop *(ebp+0x14) 1)
11022     # never gets here
11023 
11024 type-name:  # index: int -> result/eax: (addr array byte)
11025     # . prologue
11026     55/push-ebp
11027     89/<- %ebp 4/r32/esp
11028     #
11029     (index Type-id *(ebp+8))
11030 $type-name:end:
11031     # . epilogue
11032     89/<- %esp 5/r32/ebp
11033     5d/pop-to-ebp
11034     c3/return
11035 
11036 index:  # arr: (addr stream (handle array byte)), index: int -> result/eax: (addr array byte)
11037     # . prologue
11038     55/push-ebp
11039     89/<- %ebp 4/r32/esp
11040     # . save registers
11041     56/push-esi
11042     # TODO: bounds-check index
11043     # esi = arr
11044     8b/-> *(ebp+8) 6/r32/esi
11045     # eax = index
11046     8b/-> *(ebp+0xc) 0/r32/eax
11047     # eax = *(arr + 12 + index)
11048     8b/-> *(esi+eax<<2+0xc) 0/r32/eax
11049 $index:end:
11050     # . restore registers
11051     5e/pop-to-esi
11052     # . epilogue
11053     89/<- %esp 5/r32/ebp
11054     5d/pop-to-ebp
11055     c3/return
11056 
11057 #######################################################
11058 # Compute type sizes
11059 #######################################################
11060 
11061 # Compute the sizes of all user-defined types.
11062 # We'll need the sizes of their elements, which may be other user-defined
11063 # types, which we will compute as needed.
11064 
11065 # Initially, all user-defined types have their sizes set to -2 (invalid)
11066 populate-mu-type-sizes:  # err: (addr buffered-file), ed: (addr exit-descriptor)
11067     # . prologue
11068     55/push-ebp
11069     89/<- %ebp 4/r32/esp
11070 $populate-mu-type-sizes:total-sizes:
11071     # var curr/eax: (addr typeinfo) = lookup(Program->types)
11072     (lookup *_Program-types *_Program-types->payload)  # => eax
11073     {
11074       # if (curr == null) break
11075       3d/compare-eax-and 0/imm32/null
11076       74/jump-if-= break/disp8
11077       (populate-mu-type-sizes-in-type %eax *(ebp+8) *(ebp+0xc))
11078       # curr = lookup(curr->next)
11079       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
11080       eb/jump loop/disp8
11081     }
11082 $populate-mu-type-sizes:offsets:
11083     # curr = *Program->types
11084     (lookup *_Program-types *_Program-types->payload)  # => eax
11085     {
11086       # if (curr == null) break
11087       3d/compare-eax-and 0/imm32/null
11088       74/jump-if-= break/disp8
11089       (populate-mu-type-offsets %eax *(ebp+8) *(ebp+0xc))
11090       # curr = curr->next
11091       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
11092       eb/jump loop/disp8
11093     }
11094 $populate-mu-type-sizes:end:
11095     # . epilogue
11096     89/<- %esp 5/r32/ebp
11097     5d/pop-to-ebp
11098     c3/return
11099 
11100 # compute sizes of all fields, recursing as necessary
11101 # sum up all their sizes to arrive at total size
11102 # fields may be out of order, but that doesn't affect the answer
11103 populate-mu-type-sizes-in-type:  # T: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
11104     # . prologue
11105     55/push-ebp
11106     89/<- %ebp 4/r32/esp
11107     # . save registers
11108     50/push-eax
11109     51/push-ecx
11110     52/push-edx
11111     56/push-esi
11112     57/push-edi
11113     # esi = T
11114     8b/-> *(ebp+8) 6/r32/esi
11115     # if T is already computed, return
11116     81 7/subop/compare *(esi+0xc) 0/imm32  # Typeinfo-total-size-in-bytes
11117     0f 8d/jump-if->= $populate-mu-type-sizes-in-type:end/disp32
11118     # if T is being computed, abort
11119     81 7/subop/compare *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
11120     0f 84/jump-if-= $populate-mu-type-sizes-in-type:abort/disp32
11121     # tag T (-2 to -1) to avoid infinite recursion
11122     c7 0/subop/copy *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
11123     # var total-size/edi: int = 0
11124     bf/copy-to-edi 0/imm32
11125     # - for every field, if it's a user-defined type, compute its size
11126     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
11127     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
11128     89/<- %ecx 0/r32/eax
11129     # var table-size/edx: int = table->write
11130     8b/-> *ecx 2/r32/edx  # stream-write
11131     # var curr/ecx: (addr table_row) = table->data
11132     8d/copy-address *(ecx+0xc) 1/r32/ecx
11133     # var max/edx: (addr table_row) = table->data + table->write
11134     8d/copy-address *(ecx+edx) 2/r32/edx
11135     {
11136 $populate-mu-type-sizes-in-type:loop:
11137       # if (curr >= max) break
11138       39/compare %ecx 2/r32/edx
11139       73/jump-if-addr>= break/disp8
11140       # var t/eax: (addr typeinfo-entry) = lookup(curr->value)
11141       (lookup *(ecx+8) *(ecx+0xc))  # => eax
11142       # if (t->input-var == 0) silently ignore it; we'll emit a nice error message while type-checking
11143       81 7/subop/compare *eax 0/imm32  # Typeinfo-entry-input-var
11144       74/jump-if-= $populate-mu-type-sizes-in-type:end/disp8
11145       # compute size of t->input-var
11146       (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
11147       (compute-size-of-var %eax *(ebp+0xc) *(ebp+0x10))  # => eax
11148       # result += eax
11149       01/add-to %edi 0/r32/eax
11150       # curr += row-size
11151       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
11152       #
11153       eb/jump loop/disp8
11154     }
11155     # - save result
11156     89/<- *(esi+0xc) 7/r32/edi  # Typeinfo-total-size-in-bytes
11157 $populate-mu-type-sizes-in-type:end:
11158     # . restore registers
11159     5f/pop-to-edi
11160     5e/pop-to-esi
11161     5a/pop-to-edx
11162     59/pop-to-ecx
11163     58/pop-to-eax
11164     # . epilogue
11165     89/<- %esp 5/r32/ebp
11166     5d/pop-to-ebp
11167     c3/return
11168 
11169 $populate-mu-type-sizes-in-type:abort:
11170     (write-buffered *(ebp+0xc) "cycle in type definitions\n")
11171     (flush *(ebp+0xc))
11172     (stop *(ebp+0x10) 1)
11173     # never gets here
11174 
11175 # Analogous to size-of, except we need to compute what size-of can just read
11176 # off the right data structures.
11177 compute-size-of-var:  # in: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
11178     # . prologue
11179     55/push-ebp
11180     89/<- %ebp 4/r32/esp
11181     # . push registers
11182     51/push-ecx
11183     # var t/ecx: (addr type-tree) = lookup(v->type)
11184     8b/-> *(ebp+8) 1/r32/ecx
11185     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
11186     89/<- %ecx 0/r32/eax
11187     # if (t->is-atom == false) t = lookup(t->left)
11188     {
11189       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
11190       75/jump-if-!= break/disp8
11191       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
11192       89/<- %ecx 0/r32/eax
11193     }
11194     # TODO: ensure t is an atom
11195     (compute-size-of-type-id *(ecx+4) *(ebp+0xc) *(ebp+0x10))  # Type-tree-value => eax
11196 $compute-size-of-var:end:
11197     # . restore registers
11198     59/pop-to-ecx
11199     # . epilogue
11200     89/<- %esp 5/r32/ebp
11201     5d/pop-to-ebp
11202     c3/return
11203 
11204 compute-size-of-type-id:  # t: type-id, err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
11205     # . prologue
11206     55/push-ebp
11207     89/<- %ebp 4/r32/esp
11208     # . save registers
11209     51/push-ecx
11210     # var out/ecx: (handle typeinfo)
11211     68/push 0/imm32
11212     68/push 0/imm32
11213     89/<- %ecx 4/r32/esp
11214     # eax = t
11215     8b/-> *(ebp+8) 0/r32/eax
11216     # if t is a literal, return 0
11217     3d/compare-eax-and 0/imm32/literal
11218     0f 84/jump-if-= $compute-size-of-type-id:end/disp32  # eax changes type from type-id to int
11219     # if t is a byte, return 4 (because we don't really support non-multiples of 4)
11220     3d/compare-eax-and 8/imm32/byte
11221     {
11222       75/jump-if-!= break/disp8
11223       b8/copy-to-eax 4/imm32
11224       eb/jump $compute-size-of-type-id:end/disp8
11225     }
11226     # if t is a handle, return 8
11227     3d/compare-eax-and 4/imm32/handle
11228     {
11229       75/jump-if-!= break/disp8
11230       b8/copy-to-eax 8/imm32
11231       eb/jump $compute-size-of-type-id:end/disp8  # eax changes type from type-id to int
11232     }
11233     # if t is a slice, return 8
11234     3d/compare-eax-and 0xc/imm32/slice
11235     {
11236       75/jump-if-!= break/disp8
11237       b8/copy-to-eax 8/imm32
11238       eb/jump $compute-size-of-type-id:end/disp8  # eax changes type from type-id to int
11239     }
11240     # if t is a user-defined type, compute its size
11241     # TODO: support non-atom type
11242     (find-typeinfo %eax %ecx)
11243     {
11244       81 7/subop/compare *ecx 0/imm32
11245       74/jump-if-= break/disp8
11246 $compute-size-of-type-id:user-defined:
11247       (lookup *ecx *(ecx+4))  # => eax
11248       (populate-mu-type-sizes-in-type %eax *(ebp+0xc) *(ebp+0x10))
11249       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
11250       eb/jump $compute-size-of-type-id:end/disp8
11251     }
11252     # otherwise return the word size
11253     b8/copy-to-eax 4/imm32
11254 $compute-size-of-type-id:end:
11255     # . reclaim locals
11256     81 0/subop/add %esp 8/imm32
11257     # . restore registers
11258     59/pop-to-ecx
11259     # . epilogue
11260     89/<- %esp 5/r32/ebp
11261     5d/pop-to-ebp
11262     c3/return
11263 
11264 # at this point we have total sizes for all user-defined types
11265 # compute offsets for each element
11266 # complication: fields may be out of order
11267 populate-mu-type-offsets:  # in: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
11268     # . prologue
11269     55/push-ebp
11270     89/<- %ebp 4/r32/esp
11271     # . save registers
11272     50/push-eax
11273     51/push-ecx
11274     52/push-edx
11275     53/push-ebx
11276     56/push-esi
11277     57/push-edi
11278 #?     (dump-typeinfos "aaa\n")
11279     # var curr-offset/edi: int = 0
11280     bf/copy-to-edi 0/imm32
11281     # var table/ecx: (addr table string_key (handle typeinfo-entry)) = lookup(in->fields)
11282     8b/-> *(ebp+8) 1/r32/ecx
11283     (lookup *(ecx+4) *(ecx+8))  # Typeinfo-fields Typeinfo-fields => eax
11284     89/<- %ecx 0/r32/eax
11285     # var num-elems/edx: int = table->write / Typeinfo-fields-row-size
11286     8b/-> *ecx 2/r32/edx  # stream-write
11287     c1 5/subop/shift-right-logical  %edx 4/imm8
11288     # var i/ebx: int = 0
11289     bb/copy-to-ebx 0/imm32
11290     {
11291 $populate-mu-type-offsets:loop:
11292       39/compare %ebx 2/r32/edx
11293       0f 8d/jump-if->= break/disp32
11294 #?       (write-buffered Stderr "looking up index ")
11295 #?       (write-int32-hex-buffered Stderr %ebx)
11296 #?       (write-buffered Stderr " in ")
11297 #?       (write-int32-hex-buffered Stderr *(ebp+8))
11298 #?       (write-buffered Stderr Newline)
11299 #?       (flush Stderr)
11300       # var v/esi: (addr typeinfo-entry)
11301       (locate-typeinfo-entry-with-index %ecx %ebx *(ebp+0xc) *(ebp+0x10))  # => eax
11302       89/<- %esi 0/r32/eax
11303       # if v is null, silently move on; we'll emit a nice error message while type-checking
11304       81 7/subop/compare %esi 0/imm32  # Typeinfo-entry-input-var
11305       74/jump-if-= $populate-mu-type-offsets:end/disp8
11306       # if (v->input-var == 0) silently ignore v; we'll emit a nice error message while type-checking
11307       81 7/subop/compare *esi 0/imm32  # Typeinfo-entry-input-var
11308       74/jump-if-= $populate-mu-type-offsets:end/disp8
11309       # v->output-var->offset = curr-offset
11310       # . eax: (addr var)
11311       (lookup *(esi+0xc) *(esi+0x10))  # Typeinfo-entry-output-var Typeinfo-entry-output-var => eax
11312       89/<- *(eax+0x14) 7/r32/edi  # Var-offset
11313       # curr-offset += size-of(v->input-var)
11314       (lookup *esi *(esi+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
11315       (size-of %eax)  # => eax
11316       01/add-to %edi 0/r32/eax
11317       # ++i
11318       43/increment-ebx
11319       e9/jump loop/disp32
11320     }
11321 $populate-mu-type-offsets:end:
11322     # . restore registers
11323     5f/pop-to-edi
11324     5e/pop-to-esi
11325     5b/pop-to-ebx
11326     5a/pop-to-edx
11327     59/pop-to-ecx
11328     58/pop-to-eax
11329     # . epilogue
11330     89/<- %esp 5/r32/ebp
11331     5d/pop-to-ebp
11332     c3/return
11333 
11334 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)
11335     # . prologue
11336     55/push-ebp
11337     89/<- %ebp 4/r32/esp
11338     # . save registers
11339     51/push-ecx
11340     52/push-edx
11341     53/push-ebx
11342     56/push-esi
11343     57/push-edi
11344     # esi = table
11345     8b/-> *(ebp+8) 6/r32/esi
11346     # var curr/ecx: (addr row (handle array byte) (handle typeinfo-entry)) = table->data
11347     8d/copy-address *(esi+0xc) 1/r32/ecx
11348     # var max/edx: (addr byte) = &table->data[table->write]
11349     8b/-> *esi 2/r32/edx
11350     8d/copy-address *(ecx+edx) 2/r32/edx
11351     {
11352 $locate-typeinfo-entry-with-index:loop:
11353       39/compare %ecx 2/r32/edx
11354       73/jump-if-addr>= break/disp8
11355       # var v/eax: (addr typeinfo-entry)
11356       (lookup *(ecx+8) *(ecx+0xc))  # => eax
11357       # if (v->index == idx) return v
11358       8b/-> *(eax+8) 3/r32/ebx  # Typeinfo-entry-index
11359 #?       (write-buffered Stderr "comparing ")
11360 #?       (write-int32-hex-buffered Stderr %ebx)
11361 #?       (write-buffered Stderr " and ")
11362 #?       (write-int32-hex-buffered Stderr *(ebp+0xc))
11363 #?       (write-buffered Stderr Newline)
11364 #?       (flush Stderr)
11365       39/compare *(ebp+0xc) 3/r32/ebx
11366       74/jump-if-= $locate-typeinfo-entry-with-index:end/disp8
11367       # curr += Typeinfo-entry-size
11368       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-entry-size
11369       #
11370       eb/jump loop/disp8
11371     }
11372     # return 0
11373     b8/copy-to-eax 0/imm32
11374 $locate-typeinfo-entry-with-index:end:
11375 #?     (write-buffered Stderr "returning ")
11376 #?     (write-int32-hex-buffered Stderr %eax)
11377 #?     (write-buffered Stderr Newline)
11378 #?     (flush Stderr)
11379     # . restore registers
11380     5f/pop-to-edi
11381     5e/pop-to-esi
11382     5b/pop-to-ebx
11383     5a/pop-to-edx
11384     59/pop-to-ecx
11385     # . epilogue
11386     89/<- %esp 5/r32/ebp
11387     5d/pop-to-ebp
11388     c3/return
11389 
11390 dump-typeinfos:  # hdr: (addr array byte)
11391     # . prologue
11392     55/push-ebp
11393     89/<- %ebp 4/r32/esp
11394     # . save registers
11395     50/push-eax
11396     #
11397     (write-buffered Stderr *(ebp+8))
11398     (flush Stderr)
11399     # var curr/eax: (addr typeinfo) = lookup(Program->types)
11400     (lookup *_Program-types *_Program-types->payload)  # => eax
11401     {
11402       # if (curr == null) break
11403       3d/compare-eax-and 0/imm32
11404       74/jump-if-= break/disp8
11405       (write-buffered Stderr "---\n")
11406       (flush Stderr)
11407       (dump-typeinfo %eax)
11408       # curr = lookup(curr->next)
11409       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
11410       eb/jump loop/disp8
11411     }
11412 $dump-typeinfos:end:
11413     # . restore registers
11414     58/pop-to-eax
11415     # . epilogue
11416     89/<- %esp 5/r32/ebp
11417     5d/pop-to-ebp
11418     c3/return
11419 
11420 dump-typeinfo:  # in: (addr typeinfo)
11421     # . prologue
11422     55/push-ebp
11423     89/<- %ebp 4/r32/esp
11424     # . save registers
11425     50/push-eax
11426     51/push-ecx
11427     52/push-edx
11428     53/push-ebx
11429     56/push-esi
11430     57/push-edi
11431     # esi = in
11432     8b/-> *(ebp+8) 6/r32/esi
11433     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
11434     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
11435     89/<- %ecx 0/r32/eax
11436     (write-buffered Stderr "id:")
11437     (write-int32-hex-buffered Stderr *esi)
11438     (write-buffered Stderr "\n")
11439     (write-buffered Stderr "fields @ ")
11440     (write-int32-hex-buffered Stderr %ecx)
11441     (write-buffered Stderr Newline)
11442     (flush Stderr)
11443     (write-buffered Stderr "  write: ")
11444     (write-int32-hex-buffered Stderr *ecx)
11445     (write-buffered Stderr Newline)
11446     (flush Stderr)
11447     (write-buffered Stderr "  read: ")
11448     (write-int32-hex-buffered Stderr *(ecx+4))
11449     (write-buffered Stderr Newline)
11450     (flush Stderr)
11451     (write-buffered Stderr "  size: ")
11452     (write-int32-hex-buffered Stderr *(ecx+8))
11453     (write-buffered Stderr Newline)
11454     (flush Stderr)
11455     # var table-size/edx: int = table->write
11456     8b/-> *ecx 2/r32/edx  # stream-write
11457     # var curr/ecx: (addr table_row) = table->data
11458     8d/copy-address *(ecx+0xc) 1/r32/ecx
11459     # var max/edx: (addr table_row) = table->data + table->write
11460     8d/copy-address *(ecx+edx) 2/r32/edx
11461     {
11462 $dump-typeinfo:loop:
11463       # if (curr >= max) break
11464       39/compare %ecx 2/r32/edx
11465       0f 83/jump-if-addr>= break/disp32
11466       (write-buffered Stderr "  row:\n")
11467       (write-buffered Stderr "    key: ")
11468       (write-int32-hex-buffered Stderr *ecx)
11469       (write-buffered Stderr ",")
11470       (write-int32-hex-buffered Stderr *(ecx+4))
11471       (write-buffered Stderr " = '")
11472       (lookup *ecx *(ecx+4))
11473       (write-buffered Stderr %eax)
11474       (write-buffered Stderr "' @ ")
11475       (write-int32-hex-buffered Stderr %eax)
11476       (write-buffered Stderr Newline)
11477       (flush Stderr)
11478       (write-buffered Stderr "    value: ")
11479       (write-int32-hex-buffered Stderr *(ecx+8))
11480       (write-buffered Stderr ",")
11481       (write-int32-hex-buffered Stderr *(ecx+0xc))
11482       (write-buffered Stderr " = typeinfo-entry@")
11483       (lookup *(ecx+8) *(ecx+0xc))
11484       (write-int32-hex-buffered Stderr %eax)
11485       (write-buffered Stderr Newline)
11486       (flush Stderr)
11487       (write-buffered Stderr "        input var@")
11488       (dump-var 5 %eax)
11489       (lookup *(ecx+8) *(ecx+0xc))
11490       (write-buffered Stderr "        index: ")
11491       (write-int32-hex-buffered Stderr *(eax+8))
11492       (write-buffered Stderr Newline)
11493       (flush Stderr)
11494       (write-buffered Stderr "        output var@")
11495       8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
11496       (dump-var 5 %eax)
11497       (flush Stderr)
11498       # curr += row-size
11499       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
11500       #
11501       e9/jump loop/disp32
11502     }
11503 $dump-typeinfo:end:
11504     # . restore registers
11505     5f/pop-to-edi
11506     5e/pop-to-esi
11507     5b/pop-to-ebx
11508     5a/pop-to-edx
11509     59/pop-to-ecx
11510     58/pop-to-eax
11511     # . epilogue
11512     89/<- %esp 5/r32/ebp
11513     5d/pop-to-ebp
11514     c3/return
11515 
11516 dump-var:  # indent: int, v: (addr handle var)
11517     # . prologue
11518     55/push-ebp
11519     89/<- %ebp 4/r32/esp
11520     # . save registers
11521     50/push-eax
11522     53/push-ebx
11523     # eax = v
11524     8b/-> *(ebp+0xc) 0/r32/eax
11525     #
11526     (write-int32-hex-buffered Stderr *eax)
11527     (write-buffered Stderr ",")
11528     (write-int32-hex-buffered Stderr *(eax+4))
11529     (write-buffered Stderr "->")
11530     (lookup *eax *(eax+4))
11531     (write-int32-hex-buffered Stderr %eax)
11532     (write-buffered Stderr Newline)
11533     (flush Stderr)
11534     {
11535       3d/compare-eax-and 0/imm32
11536       0f 84/jump-if-= break/disp32
11537       (emit-indent Stderr *(ebp+8))
11538       (write-buffered Stderr "name: ")
11539       89/<- %ebx 0/r32/eax
11540       (write-int32-hex-buffered Stderr *ebx)  # Var-name
11541       (write-buffered Stderr ",")
11542       (write-int32-hex-buffered Stderr *(ebx+4))  # Var-name
11543       (write-buffered Stderr "->")
11544       (lookup *ebx *(ebx+4))  # Var-name
11545       (write-int32-hex-buffered Stderr %eax)
11546       {
11547         3d/compare-eax-and 0/imm32
11548         74/jump-if-= break/disp8
11549         (write-buffered Stderr Space)
11550         (write-buffered Stderr %eax)
11551       }
11552       (write-buffered Stderr Newline)
11553       (flush Stderr)
11554       (emit-indent Stderr *(ebp+8))
11555       (write-buffered Stderr "block depth: ")
11556       (write-int32-hex-buffered Stderr *(ebx+0x10))  # Var-block-depth
11557       (write-buffered Stderr Newline)
11558       (flush Stderr)
11559       (emit-indent Stderr *(ebp+8))
11560       (write-buffered Stderr "stack offset: ")
11561       (write-int32-hex-buffered Stderr *(ebx+0x14))  # Var-offset
11562       (write-buffered Stderr Newline)
11563       (flush Stderr)
11564       (emit-indent Stderr *(ebp+8))
11565       (write-buffered Stderr "reg: ")
11566       (write-int32-hex-buffered Stderr *(ebx+0x18))  # Var-register
11567       (write-buffered Stderr ",")
11568       (write-int32-hex-buffered Stderr *(ebx+0x1c))  # Var-register
11569       (write-buffered Stderr "->")
11570       (flush Stderr)
11571       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register
11572       (write-int32-hex-buffered Stderr %eax)
11573       {
11574         3d/compare-eax-and 0/imm32
11575         74/jump-if-= break/disp8
11576         (write-buffered Stderr Space)
11577         (write-buffered Stderr %eax)
11578       }
11579       (write-buffered Stderr Newline)
11580       (flush Stderr)
11581     }
11582 $dump-var:end:
11583     # . restore registers
11584     5b/pop-to-ebx
11585     58/pop-to-eax
11586     # . epilogue
11587     89/<- %esp 5/r32/ebp
11588     5d/pop-to-ebp
11589     c3/return
11590 
11591 #######################################################
11592 # Type-checking
11593 #######################################################
11594 
11595 check-mu-types:  # err: (addr buffered-file), ed: (addr exit-descriptor)
11596     # . prologue
11597     55/push-ebp
11598     89/<- %ebp 4/r32/esp
11599     # . save registers
11600     50/push-eax
11601     # var curr/eax: (addr function) = lookup(Program->functions)
11602     (lookup *_Program-functions *_Program-functions->payload)  # => eax
11603     {
11604 $check-mu-types:loop:
11605       # if (curr == null) break
11606       3d/compare-eax-and 0/imm32
11607       0f 84/jump-if-= break/disp32
11608 +--  8 lines: #?       # dump curr->name ------------------------------------------------------------------------------------------------------------------------------------------------
11616       (check-mu-function %eax *(ebp+8) *(ebp+0xc))
11617       # curr = lookup(curr->next)
11618       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
11619       e9/jump loop/disp32
11620     }
11621 $check-mu-types:end:
11622     # . restore registers
11623     58/pop-to-eax
11624     # . epilogue
11625     89/<- %esp 5/r32/ebp
11626     5d/pop-to-ebp
11627     c3/return
11628 
11629 check-mu-function:  # fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11630     # . prologue
11631     55/push-ebp
11632     89/<- %ebp 4/r32/esp
11633     # . save registers
11634     50/push-eax
11635     # eax = f
11636     8b/-> *(ebp+8) 0/r32/eax
11637     # TODO: anything to check in header?
11638     # var body/eax: (addr block) = lookup(f->body)
11639     (lookup *(eax+0x18) *(eax+0x1c))  # Function-body Function-body => eax
11640     (check-mu-block %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10))
11641 $check-mu-function:end:
11642     # . restore registers
11643     58/pop-to-eax
11644     # . epilogue
11645     89/<- %esp 5/r32/ebp
11646     5d/pop-to-ebp
11647     c3/return
11648 
11649 check-mu-block:  # block: (addr block), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11650     # . prologue
11651     55/push-ebp
11652     89/<- %ebp 4/r32/esp
11653     # . save registers
11654     50/push-eax
11655     # eax = block
11656     8b/-> *(ebp+8) 0/r32/eax
11657     # var stmts/eax: (addr list stmt) = lookup(block->statements)
11658     (lookup *(eax+4) *(eax+8))  # Block-stmts Block-stmts => eax
11659     #
11660     {
11661 $check-mu-block:check-empty:
11662       3d/compare-eax-and 0/imm32
11663       0f 84/jump-if-= break/disp32
11664       # emit block->statements
11665       (check-mu-stmt-list %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11666     }
11667 $check-mu-block:end:
11668     # . restore registers
11669     58/pop-to-eax
11670     # . epilogue
11671     89/<- %esp 5/r32/ebp
11672     5d/pop-to-ebp
11673     c3/return
11674 
11675 check-mu-stmt-list:  # stmts: (addr list stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11676     # . prologue
11677     55/push-ebp
11678     89/<- %ebp 4/r32/esp
11679     # . save registers
11680     50/push-eax
11681     56/push-esi
11682     # esi = stmts
11683     8b/-> *(ebp+8) 6/r32/esi
11684     {
11685 $check-mu-stmt-list:loop:
11686       81 7/subop/compare %esi 0/imm32
11687       0f 84/jump-if-= break/disp32
11688       # var curr-stmt/eax: (addr stmt) = lookup(stmts->value)
11689       (lookup *esi *(esi+4))  # List-value List-value => eax
11690       {
11691 $check-mu-stmt-list:check-for-block:
11692         81 7/subop/compare *eax 0/imm32/block  # Stmt-tag
11693         75/jump-if-!= break/disp8
11694 $check-mu-stmt-list:block:
11695         (check-mu-block %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11696         eb/jump $check-mu-stmt-list:continue/disp8
11697       }
11698       {
11699 $check-mu-stmt-list:check-for-stmt1:
11700         81 7/subop/compare *eax 1/imm32/stmt1  # Stmt-tag
11701         0f 85/jump-if-!= break/disp32
11702 $check-mu-stmt-list:stmt1:
11703         (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11704         eb/jump $check-mu-stmt-list:continue/disp8
11705       }
11706       {
11707 $check-mu-stmt-list:check-for-reg-var-def:
11708         81 7/subop/compare *eax 3/imm32/reg-var-def  # Stmt-tag
11709         0f 85/jump-if-!= break/disp32
11710 $check-mu-stmt-list:reg-var-def:
11711         (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11712         eb/jump $check-mu-stmt-list:continue/disp8
11713       }
11714 $check-mu-stmt-list:continue:
11715       # TODO: raise an error on unrecognized Stmt-tag
11716       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
11717       89/<- %esi 0/r32/eax
11718       e9/jump loop/disp32
11719     }
11720 $check-mu-stmt-list:end:
11721     # . restore registers
11722     5e/pop-to-esi
11723     58/pop-to-eax
11724     # . epilogue
11725     89/<- %esp 5/r32/ebp
11726     5d/pop-to-ebp
11727     c3/return
11728 
11729 check-mu-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11730     # . prologue
11731     55/push-ebp
11732     89/<- %ebp 4/r32/esp
11733     # . save registers
11734     50/push-eax
11735     # - if stmt's operation matches a primitive, check against it
11736     (has-primitive-name? *(ebp+8))  # => eax
11737     3d/compare-eax-and 0/imm32/false
11738     {
11739       74/jump-if-= break/disp8
11740       (check-mu-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11741       e9/jump $check-mu-stmt:end/disp32
11742     }
11743     # - otherwise find a function to check against
11744     # var f/eax: (addr function) = lookup(*Program->functions)
11745     (lookup *_Program-functions *_Program-functions->payload)  # => eax
11746     (find-matching-function %eax *(ebp+8))  # => eax
11747     3d/compare-eax-and 0/imm32
11748     {
11749       74/jump-if-= break/disp8
11750       (check-mu-call *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11751       eb/jump $check-mu-stmt:end/disp8
11752     }
11753     # var f/eax: (addr function) = lookup(*Program->signatures)
11754     (lookup *_Program-signatures *_Program-signatures->payload)  # => eax
11755     (find-matching-function %eax *(ebp+8))  # => eax
11756     3d/compare-eax-and 0/imm32
11757     {
11758       74/jump-if-= break/disp8
11759       (check-mu-call *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11760       eb/jump $check-mu-stmt:end/disp8
11761     }
11762     # - otherwise abort
11763     e9/jump $check-mu-stmt:unknown-call/disp32
11764 $check-mu-stmt:end:
11765     # . restore registers
11766     58/pop-to-eax
11767     # . epilogue
11768     89/<- %esp 5/r32/ebp
11769     5d/pop-to-ebp
11770     c3/return
11771 
11772 $check-mu-stmt:unknown-call:
11773     (write-buffered *(ebp+0x10) "unknown function '")
11774     8b/-> *(ebp+8) 0/r32/eax
11775     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
11776     (write-buffered *(ebp+0x10) %eax)
11777     (write-buffered *(ebp+0x10) "'\n")
11778     (flush *(ebp+0x10))
11779     (stop *(ebp+0x14) 1)
11780     # never gets here
11781 
11782 has-primitive-name?:  # stmt: (addr stmt) -> result/eax: boolean
11783     # . prologue
11784     55/push-ebp
11785     89/<- %ebp 4/r32/esp
11786     # . save registers
11787     51/push-ecx
11788     56/push-esi
11789     # var name/esi: (addr array byte) = lookup(stmt->operation)
11790     8b/-> *(ebp+8) 6/r32/esi
11791     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
11792     89/<- %esi 0/r32/eax
11793     # if (name == "get") return true
11794     (string-equal? %esi "get")  # => eax
11795     3d/compare-eax-and 0/imm32/false
11796     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11797     # if (name == "index") return true
11798     (string-equal? %esi "index")  # => eax
11799     3d/compare-eax-and 0/imm32/false
11800     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11801     # if (name == "length") return true
11802     (string-equal? %esi "length")  # => eax
11803     3d/compare-eax-and 0/imm32/false
11804     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11805     # if (name == "compute-offset") return true
11806     (string-equal? %esi "compute-offset")  # => eax
11807     3d/compare-eax-and 0/imm32/false
11808     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11809     # if (name == "allocate") return true
11810     (string-equal? %esi "allocate")  # => eax
11811     3d/compare-eax-and 0/imm32/false
11812     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11813     # if (name == "populate") return true
11814     (string-equal? %esi "populate")  # => eax
11815     3d/compare-eax-and 0/imm32/false
11816     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11817     # if (name == "populate-stream") return true
11818     (string-equal? %esi "populate-stream")  # => eax
11819     3d/compare-eax-and 0/imm32/false
11820     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11821     # if (name == "read-from-stream") return true
11822     (string-equal? %esi "read-from-stream")  # => eax
11823     3d/compare-eax-and 0/imm32/false
11824     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11825     # if (name == "write-to-stream") return true
11826     (string-equal? %esi "write-to-stream")  # => eax
11827     3d/compare-eax-and 0/imm32/false
11828     0f 85/jump-if-!= $has-primitive-name?:end/disp32
11829     # var curr/ecx: (addr primitive) = Primitives
11830     b9/copy-to-ecx Primitives/imm32
11831     {
11832 $has-primitive-name?:loop:
11833       # if (curr == null) break
11834       81 7/subop/compare %ecx 0/imm32
11835       74/jump-if-= break/disp8
11836       # if (primitive->name == name) return true
11837       (lookup *ecx *(ecx+4))  # Primitive-name Primitive-name => eax
11838       (string-equal? %esi %eax)  # => eax
11839       3d/compare-eax-and 0/imm32/false
11840       75/jump-if-!= $has-primitive-name?:end/disp8
11841 $has-primitive-name?:next-primitive:
11842       # curr = curr->next
11843       (lookup *(ecx+0x38) *(ecx+0x3c))  # Primitive-next Primitive-next => eax
11844       89/<- %ecx 0/r32/eax
11845       #
11846       e9/jump loop/disp32
11847     }
11848     # return null
11849     b8/copy-to-eax 0/imm32
11850 $has-primitive-name?:end:
11851     # . restore registers
11852     5e/pop-to-esi
11853     59/pop-to-ecx
11854     # . epilogue
11855     89/<- %esp 5/r32/ebp
11856     5d/pop-to-ebp
11857     c3/return
11858 
11859 check-mu-primitive:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11860     # . prologue
11861     55/push-ebp
11862     89/<- %ebp 4/r32/esp
11863     # . save registers
11864     50/push-eax
11865     51/push-ecx
11866     # var op/ecx: (addr array byte) = lookup(stmt->operation)
11867     8b/-> *(ebp+8) 0/r32/eax
11868     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
11869     89/<- %ecx 0/r32/eax
11870     # if (op == "copy") check-mu-copy-stmt
11871     {
11872       (string-equal? %ecx "copy")  # => eax
11873       3d/compare-eax-and 0/imm32/false
11874       74/jump-if-= break/disp8
11875       (check-mu-copy-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11876       e9/jump $check-mu-primitive:end/disp32
11877     }
11878     # if (op == "copy-to") check-mu-copy-to-stmt
11879     {
11880       (string-equal? %ecx "copy-to")  # => eax
11881       3d/compare-eax-and 0/imm32/false
11882       74/jump-if-= break/disp8
11883       (check-mu-copy-to-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11884       e9/jump $check-mu-primitive:end/disp32
11885     }
11886     # if (op == "compare") check-mu-compare-stmt
11887     {
11888       (string-equal? %ecx "compare")  # => eax
11889       3d/compare-eax-and 0/imm32/false
11890       74/jump-if-= break/disp8
11891       (check-mu-compare-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11892       e9/jump $check-mu-primitive:end/disp32
11893     }
11894     # if (op == "address") check-mu-address-stmt
11895     {
11896       (string-equal? %ecx "address")  # => eax
11897       3d/compare-eax-and 0/imm32/false
11898       74/jump-if-= break/disp8
11899       (check-mu-address-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11900       e9/jump $check-mu-primitive:end/disp32
11901     }
11902     # if (op == "get") check-mu-get-stmt
11903     {
11904       (string-equal? %ecx "get")  # => eax
11905       3d/compare-eax-and 0/imm32/false
11906       74/jump-if-= break/disp8
11907       (check-mu-get-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11908       e9/jump $check-mu-primitive:end/disp32
11909     }
11910     # if (op == "index") check-mu-index-stmt
11911     {
11912       (string-equal? %ecx "index")  # => eax
11913       3d/compare-eax-and 0/imm32/false
11914       74/jump-if-= break/disp8
11915       (check-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11916       e9/jump $check-mu-primitive:end/disp32
11917     }
11918     # if (op == "length") check-mu-length-stmt
11919     {
11920       (string-equal? %ecx "length")  # => eax
11921       3d/compare-eax-and 0/imm32/false
11922       74/jump-if-= break/disp8
11923       (check-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11924       e9/jump $check-mu-primitive:end/disp32
11925     }
11926     # if (op == "compute-offset") check-mu-compute-offset-stmt
11927     {
11928       (string-equal? %ecx "compute-offset")  # => eax
11929       3d/compare-eax-and 0/imm32/false
11930       74/jump-if-= break/disp8
11931       (check-mu-compute-offset-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11932       e9/jump $check-mu-primitive:end/disp32
11933     }
11934     # if (op == "allocate") check-mu-allocate-stmt
11935     {
11936       (string-equal? %ecx "allocate")  # => eax
11937       3d/compare-eax-and 0/imm32/false
11938       74/jump-if-= break/disp8
11939       (check-mu-allocate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11940       e9/jump $check-mu-primitive:end/disp32
11941     }
11942     # if (op == "populate") check-mu-populate-stmt
11943     {
11944       (string-equal? %ecx "populate")  # => eax
11945       3d/compare-eax-and 0/imm32/false
11946       74/jump-if-= break/disp8
11947       (check-mu-populate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11948       e9/jump $check-mu-primitive:end/disp32
11949     }
11950     # if (op == "populate-stream") check-mu-populate-stream-stmt
11951     {
11952       (string-equal? %ecx "populate-stream")  # => eax
11953       3d/compare-eax-and 0/imm32/false
11954       74/jump-if-= break/disp8
11955       (check-mu-populate-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11956       e9/jump $check-mu-primitive:end/disp32
11957     }
11958     # if (op == "read-from-stream") check-mu-read-from-stream-stmt
11959     {
11960       (string-equal? %ecx "read-from-stream")  # => eax
11961       3d/compare-eax-and 0/imm32/false
11962       74/jump-if-= break/disp8
11963       (check-mu-read-from-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11964       e9/jump $check-mu-primitive:end/disp32
11965     }
11966     # if (op == "write-to-stream") check-mu-write-to-stream-stmt
11967     {
11968       (string-equal? %ecx "write-to-stream")  # => eax
11969       3d/compare-eax-and 0/imm32/false
11970       74/jump-if-= break/disp8
11971       (check-mu-write-to-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11972       e9/jump $check-mu-primitive:end/disp32
11973     }
11974     # otherwise check-numberlike-stmt
11975     (check-mu-numberlike-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11976 $check-mu-primitive:end:
11977     # . restore registers
11978     59/pop-to-ecx
11979     58/pop-to-eax
11980     # . epilogue
11981     89/<- %esp 5/r32/ebp
11982     5d/pop-to-ebp
11983     c3/return
11984 
11985 # by default, Mu primitives should only operate on 'number-like' types
11986 check-mu-numberlike-primitive:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11987     # . prologue
11988     55/push-ebp
11989     89/<- %ebp 4/r32/esp
11990     # . save registers
11991     50/push-eax
11992     51/push-ecx
11993     56/push-esi
11994     # esi = stmt
11995     8b/-> *(ebp+8) 6/r32/esi
11996     # var gas/ecx: int = 2
11997     b9/copy-to-ecx 2/imm32
11998     # - check at most 1 output
11999     # var output/eax: (addr stmt-var) = stmt->outputs
12000     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
12001     {
12002       3d/compare-eax-and 0/imm32
12003       74/jump-if-= break/disp8
12004 $check-mu-numberlike-primitive:output:
12005       (check-mu-numberlike-output %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12006       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
12007       3d/compare-eax-and 0/imm32
12008       0f 85/jump-if-!= $check-mu-numberlike-primitive:error-too-many-outputs/disp32
12009       # check output is in a register
12010       # --gas
12011       49/decrement-ecx
12012     }
12013     # - check first inout
12014     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12015     {
12016       3d/compare-eax-and 0/imm32
12017       0f 84/jump-if-= $check-mu-numberlike-primitive:end/disp32
12018 $check-mu-numberlike-primitive:first-inout:
12019       (check-mu-numberlike-arg %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12020       # --gas
12021       49/decrement-ecx
12022     }
12023     # - check second inout
12024     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
12025     {
12026       3d/compare-eax-and 0/imm32
12027       74/jump-if-= $check-mu-numberlike-primitive:end/disp8
12028 $check-mu-numberlike-primitive:second-inout:
12029       # is a second inout allowed?
12030       81 7/subop/compare %ecx 0/imm32
12031       0f 84/jump-if-= $check-mu-numberlike-primitive:error-too-many-inouts/disp32
12032 $check-mu-numberlike-primitive:second-inout-permitted:
12033       (check-mu-numberlike-arg %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12034     }
12035 $check-mu-numberlike-primitive:third-inout:
12036     # if there's a third arg, raise an error
12037     81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
12038     0f 85/jump-if-!= $check-mu-numberlike-primitive:error-too-many-inouts/disp32
12039 $check-mu-numberlike-primitive:end:
12040     # . restore registers
12041     5e/pop-to-esi
12042     59/pop-to-ecx
12043     58/pop-to-eax
12044     # . epilogue
12045     89/<- %esp 5/r32/ebp
12046     5d/pop-to-ebp
12047     c3/return
12048 
12049 $check-mu-numberlike-primitive:error-too-many-inouts:
12050     (write-buffered *(ebp+0x10) "fn ")
12051     8b/-> *(ebp+0xc) 0/r32/eax
12052     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12053     (write-buffered *(ebp+0x10) %eax)
12054     (write-buffered *(ebp+0x10) ": stmt ")
12055     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
12056     (write-buffered *(ebp+0x10) %eax)
12057     (write-buffered *(ebp+0x10) ": too many inouts; most primitives support at most two arguments, across inouts and outputs\n")
12058     (flush *(ebp+0x10))
12059     (stop *(ebp+0x14) 1)
12060     # never gets here
12061 
12062 $check-mu-numberlike-primitive:error-too-many-outputs:
12063     (write-buffered *(ebp+0x10) "fn ")
12064     8b/-> *(ebp+0xc) 0/r32/eax
12065     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12066     (write-buffered *(ebp+0x10) %eax)
12067     (write-buffered *(ebp+0x10) ": stmt ")
12068     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
12069     (write-buffered *(ebp+0x10) %eax)
12070     (write-buffered *(ebp+0x10) ": too many outputs; most primitives support at most one output\n")
12071     (flush *(ebp+0x10))
12072     (stop *(ebp+0x14) 1)
12073     # never gets here
12074 
12075 check-mu-numberlike-arg:  # v: (addr stmt-var), 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     50/push-eax
12081     56/push-esi
12082     # var t/esi: (addr type-tree) = lookup(v->value->type)
12083     8b/-> *(ebp+8) 0/r32/eax
12084     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12085     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12086     89/<- %esi 0/r32/eax
12087 $check-mu-numberlike-arg:check-literal:
12088     # if t is an int, return
12089     (is-simple-mu-type? %esi 0)  # literal => eax
12090     3d/compare-eax-and 0/imm32/false
12091     75/jump-if-!= $check-mu-numberlike-arg:end/disp8
12092 $check-mu-numberlike-arg:check-addr:
12093     # if t is an addr and v is dereferenced, return
12094     {
12095       (is-mu-addr-type? %esi)  # => eax
12096       3d/compare-eax-and 0/imm32/false
12097       74/jump-if-= break/disp8
12098       8b/-> *(ebp+8) 0/r32/eax
12099       8b/-> *(eax+0x10) 0/r32/eax
12100       3d/compare-eax-and 0/imm32/false
12101       75/jump-if-!= $check-mu-numberlike-arg:end/disp8
12102     }
12103 $check-mu-numberlike-arg:output-checks:
12104     (check-mu-numberlike-output *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18))
12105 $check-mu-numberlike-arg:end:
12106     # . restore registers
12107     5e/pop-to-esi
12108     58/pop-to-eax
12109     # . epilogue
12110     89/<- %esp 5/r32/ebp
12111     5d/pop-to-ebp
12112     c3/return
12113 
12114 check-mu-numberlike-output:  # v: (addr stmt-var), stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12115     # . prologue
12116     55/push-ebp
12117     89/<- %ebp 4/r32/esp
12118     # . save registers
12119     50/push-eax
12120     56/push-esi
12121     # var t/esi: (addr type-tree) = lookup(v->value->type)
12122     8b/-> *(ebp+8) 0/r32/eax
12123     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12124     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12125     89/<- %esi 0/r32/eax
12126 $check-mu-numberlike-output:check-int:
12127     # if t is an int, return
12128     (is-simple-mu-type? %esi 1)  # int => eax
12129     3d/compare-eax-and 0/imm32/false
12130     75/jump-if-!= $check-mu-numberlike-output:end/disp8
12131 $check-mu-numberlike-output:check-boolean:
12132     # if t is a boolean, return
12133     (is-simple-mu-type? %esi 5)  # boolean => eax
12134     3d/compare-eax-and 0/imm32/false
12135     75/jump-if-!= $check-mu-numberlike-output:end/disp8
12136 $check-mu-numberlike-output:check-byte:
12137     # if t is a byte, return
12138     (is-simple-mu-type? %esi 8)  # byte => eax
12139     3d/compare-eax-and 0/imm32/false
12140     75/jump-if-!= $check-mu-numberlike-output:end/disp8
12141     e9/jump $check-mu-numberlike-output:fail/disp32
12142 $check-mu-numberlike-output:end:
12143     # . restore registers
12144     5e/pop-to-esi
12145     58/pop-to-eax
12146     # . epilogue
12147     89/<- %esp 5/r32/ebp
12148     5d/pop-to-ebp
12149     c3/return
12150 
12151 $check-mu-numberlike-output:fail:
12152     # otherwise raise an error
12153     (write-buffered *(ebp+0x14) "fn ")
12154     8b/-> *(ebp+0x10) 0/r32/eax
12155     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12156     (write-buffered *(ebp+0x14) %eax)
12157     (write-buffered *(ebp+0x14) ": stmt ")
12158     8b/-> *(ebp+0xc) 0/r32/eax
12159     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
12160     (write-buffered *(ebp+0x14) %eax)
12161     (write-buffered *(ebp+0x14) ": only non-addr scalar args permitted\n")
12162     (flush *(ebp+0x14))
12163     (stop *(ebp+0x18) 1)
12164     # never gets here
12165 
12166 check-mu-copy-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12167     # . prologue
12168     55/push-ebp
12169     89/<- %ebp 4/r32/esp
12170     # . save registers
12171 $check-mu-copy-stmt:end:
12172     # . restore registers
12173     # . epilogue
12174     89/<- %esp 5/r32/ebp
12175     5d/pop-to-ebp
12176     c3/return
12177 
12178 check-mu-copy-to-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12179     # . prologue
12180     55/push-ebp
12181     89/<- %ebp 4/r32/esp
12182     # . save registers
12183 $check-mu-copy-to-stmt:end:
12184     # . restore registers
12185     # . epilogue
12186     89/<- %esp 5/r32/ebp
12187     5d/pop-to-ebp
12188     c3/return
12189 
12190 check-mu-compare-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12191     # . prologue
12192     55/push-ebp
12193     89/<- %ebp 4/r32/esp
12194     # . save registers
12195 $check-mu-compare-stmt:end:
12196     # . restore registers
12197     # . epilogue
12198     89/<- %esp 5/r32/ebp
12199     5d/pop-to-ebp
12200     c3/return
12201 
12202 check-mu-address-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12203     # . prologue
12204     55/push-ebp
12205     89/<- %ebp 4/r32/esp
12206     # . save registers
12207 $check-mu-address-stmt:end:
12208     # . restore registers
12209     # . epilogue
12210     89/<- %esp 5/r32/ebp
12211     5d/pop-to-ebp
12212     c3/return
12213 
12214 check-mu-get-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12215     # . prologue
12216     55/push-ebp
12217     89/<- %ebp 4/r32/esp
12218     # . save registers
12219     50/push-eax
12220     51/push-ecx
12221     52/push-edx
12222     53/push-ebx
12223     56/push-esi
12224     57/push-edi
12225     # esi = stmt
12226     8b/-> *(ebp+8) 6/r32/esi
12227     # - check for 0 inouts
12228     # var base/ecx: (addr var) = stmt->inouts->value
12229     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12230     3d/compare-eax-and 0/imm32/false
12231     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-inouts/disp32
12232     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12233     89/<- %ecx 0/r32/eax
12234 $check-mu-get-stmt:check-base:
12235     # - check base type
12236     # if it's an 'addr', check that it's in a register
12237     # var base-type/ebx: (addr type-tree) = lookup(base->type)
12238     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
12239     89/<- %ebx 0/r32/eax
12240     {
12241       81 7/subop/compare *ebx 0/imm32/false  # Type-tree-is-atom
12242       0f 85/jump-if-!= break/disp32
12243 $check-mu-get-stmt:base-is-compound:
12244       # if (type->left != addr) break
12245       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
12246       (is-simple-mu-type? %eax 2)  # => eax
12247       3d/compare-eax-and 0/imm32/false
12248       74/jump-if-= break/disp8
12249 $check-mu-get-stmt:base-is-addr:
12250       # now check for register
12251       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
12252       0f 84/jump-if-= $check-mu-get-stmt:error-base-type-addr-but-not-register/disp32
12253 $check-mu-get-stmt:base-is-addr-in-register:
12254       # type->left is now an addr; skip it
12255       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
12256       81 7/subop/compare *(eax+0xc) 0/imm32  # Type-tree-right
12257       0f 85/jump-if-!= $check-mu-get-stmt:error-bad-base/disp32
12258 $check-mu-get-stmt:base-is-addr-to-atom-in-register:
12259       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
12260       89/<- %ebx 0/r32/eax
12261     }
12262 $check-mu-get-stmt:check-base-typeinfo:
12263     # ensure type is a container
12264     # var base-type-id/ebx: type-id = base-type->value
12265     8b/-> *(ebx+4) 3/r32/ebx  # Type-tree-value
12266     (is-container? %ebx)  # => eax
12267     3d/compare-eax-and 0/imm32/false
12268     0f 84/jump-if-= $check-mu-get-stmt:error-bad-base/disp32
12269     # var base-typeinfo/edx: (addr typeinfo) = find-typeinfo(base-type-id)
12270     # . var container/ecx: (handle typeinfo)
12271     68/push 0/imm32
12272     68/push 0/imm32
12273     89/<- %ecx 4/r32/esp
12274     # .
12275     (find-typeinfo %ebx %ecx)
12276     (lookup *ecx *(ecx+4))  # => eax
12277     # . reclaim container
12278     81 0/subop/add %esp 8/imm32
12279     # .
12280     89/<- %edx 0/r32/eax
12281     # var offset/ecx: (addr stmt-var) = stmt->inouts->next
12282     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12283     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
12284     89/<- %ecx 0/r32/eax
12285     # - check for 1 inout
12286     3d/compare-eax-and 0/imm32/false
12287     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-inouts/disp32
12288     # var offset/ecx: (addr var) = lookup(offset->value)
12289     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12290     89/<- %ecx 0/r32/eax
12291     # - check for valid field
12292     81 7/subop/compare *(ecx+0x14) -1/imm32/uninitialized  # Var-offset
12293     0f 84/jump-if-= $check-mu-get-stmt:error-bad-field/disp32
12294     # - check for too many inouts
12295     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12296     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
12297     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
12298     3d/compare-eax-and 0/imm32/false
12299     0f 85/jump-if-!= $check-mu-get-stmt:error-too-many-inouts/disp32
12300     # var output/edi: (addr var) = stmt->outputs->value
12301     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
12302     # - check for 0 outputs
12303     3d/compare-eax-and 0/imm32/false
12304     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-outputs/disp32
12305     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12306     89/<- %edi 0/r32/eax
12307 $check-mu-get-stmt:check-output-type:
12308     # - check output type
12309     # must be in register
12310     (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
12311     3d/compare-eax-and 0/imm32
12312     0f 84/jump-if-= $check-mu-get-stmt:error-output-not-in-register/disp32
12313     # must have a non-atomic type
12314     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
12315     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
12316     0f 85/jump-if-!= $check-mu-get-stmt:error-output-type-not-address/disp32
12317     # type must start with (addr ...)
12318     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
12319     (is-simple-mu-type? %eax 2)  # => eax
12320     3d/compare-eax-and 0/imm32/false
12321     0f 84/jump-if-= $check-mu-get-stmt:error-output-type-not-address/disp32
12322 $check-mu-get-stmt:check-output-type-match:
12323     # payload of addr type must match 'type' definition
12324     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
12325     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
12326     # if (payload->right == null) payload = payload->left
12327     81 7/subop/compare *(eax+0xc) 0/imm32/null  # Type-tree-right
12328     {
12329       75/jump-if-!= break/disp8
12330       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
12331     }
12332     89/<- %edi 0/r32/eax
12333     # . var output-name/ecx: (addr array byte)
12334     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
12335     89/<- %ecx 0/r32/eax
12336     # . var base-typeinfo-entry/eax: (addr handle typeinfo-entry)
12337     (lookup *(edx+4) *(edx+8))  # Typeinfo-fields Typeinfo-fields => eax
12338     (get %eax %ecx 0x10)  # => eax
12339     # .
12340     (lookup *eax *(eax+4))  # => eax
12341     (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
12342     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12343     # .
12344     (type-equal? %edi %eax)  # => eax
12345     3d/compare-eax-and 0/imm32/false
12346     0f 84/jump-if-= $check-mu-get-stmt:error-bad-output-type/disp32
12347     # - check for too many outputs
12348     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
12349     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
12350     3d/compare-eax-and 0/imm32/false
12351     0f 85/jump-if-!= $check-mu-get-stmt:error-too-many-outputs/disp32
12352 $check-mu-get-stmt:end:
12353     # . restore registers
12354     5f/pop-to-edi
12355     5e/pop-to-esi
12356     5b/pop-to-ebx
12357     5a/pop-to-edx
12358     59/pop-to-ecx
12359     58/pop-to-eax
12360     # . epilogue
12361     89/<- %esp 5/r32/ebp
12362     5d/pop-to-ebp
12363     c3/return
12364 
12365 $check-mu-get-stmt:error-too-few-inouts:
12366     (write-buffered *(ebp+0x10) "fn ")
12367     8b/-> *(ebp+0xc) 0/r32/eax
12368     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12369     (write-buffered *(ebp+0x10) %eax)
12370     (write-buffered *(ebp+0x10) ": stmt get: too few inouts (2 required)\n")
12371     (flush *(ebp+0x10))
12372     (stop *(ebp+0x14) 1)
12373     # never gets here
12374 
12375 $check-mu-get-stmt:error-too-many-inouts:
12376     (write-buffered *(ebp+0x10) "fn ")
12377     8b/-> *(ebp+0xc) 0/r32/eax
12378     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12379     (write-buffered *(ebp+0x10) %eax)
12380     (write-buffered *(ebp+0x10) ": stmt get: too many inouts (2 required)\n")
12381     (flush *(ebp+0x10))
12382     (stop *(ebp+0x14) 1)
12383     # never gets here
12384 
12385 $check-mu-get-stmt:error-too-few-outputs:
12386     (write-buffered *(ebp+0x10) "fn ")
12387     8b/-> *(ebp+0xc) 0/r32/eax
12388     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12389     (write-buffered *(ebp+0x10) %eax)
12390     (write-buffered *(ebp+0x10) ": stmt get: must have an output\n")
12391     (flush *(ebp+0x10))
12392     (stop *(ebp+0x14) 1)
12393     # never gets here
12394 
12395 $check-mu-get-stmt:error-too-many-outputs:
12396     (write-buffered *(ebp+0x10) "fn ")
12397     8b/-> *(ebp+0xc) 0/r32/eax
12398     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12399     (write-buffered *(ebp+0x10) %eax)
12400     (write-buffered *(ebp+0x10) ": stmt get: too many outputs (1 required)\n")
12401     (flush *(ebp+0x10))
12402     (stop *(ebp+0x14) 1)
12403     # never gets here
12404 
12405 $check-mu-get-stmt:error-bad-base:
12406     # error("fn " fn ": stmt get: var '" base->name "' must have a 'type' definition\n")
12407     (write-buffered *(ebp+0x10) "fn ")
12408     8b/-> *(ebp+0xc) 0/r32/eax
12409     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12410     (write-buffered *(ebp+0x10) %eax)
12411     (write-buffered *(ebp+0x10) ": stmt get: var '")
12412     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12413     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12414     (lookup *eax *(eax+4))  # Var-name Var-name => eax
12415     (write-buffered *(ebp+0x10) %eax)
12416     (write-buffered *(ebp+0x10) "' must have a 'type' definition\n")
12417     (flush *(ebp+0x10))
12418     (stop *(ebp+0x14) 1)
12419     # never gets here
12420 
12421 $check-mu-get-stmt:error-base-type-addr-but-not-register:
12422     (write-buffered *(ebp+0x10) "fn ")
12423     8b/-> *(ebp+0xc) 0/r32/eax
12424     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12425     (write-buffered *(ebp+0x10) %eax)
12426     (write-buffered *(ebp+0x10) ": stmt get: var '")
12427     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12428     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12429     (lookup *eax *(eax+4))  # Var-name Var-name => eax
12430     (write-buffered *(ebp+0x10) %eax)
12431     (write-buffered *(ebp+0x10) "' is an 'addr' type, and so must live in a register\n")
12432     (flush *(ebp+0x10))
12433     (stop *(ebp+0x14) 1)
12434     # never gets here
12435 
12436 $check-mu-get-stmt:error-bad-field:
12437     # error("fn " fn ": stmt get: type " type " has no member called '" curr->name "'\n")
12438     (write-buffered *(ebp+0x10) "fn ")
12439     8b/-> *(ebp+0xc) 0/r32/eax
12440     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12441     (write-buffered *(ebp+0x10) %eax)
12442     (write-buffered *(ebp+0x10) ": stmt get: type '")
12443     # . write(Type-id->data[tmp])
12444     bf/copy-to-edi Type-id/imm32
12445     (write-buffered *(ebp+0x10) *(edi+ebx<<2+0xc))
12446     # .
12447     (write-buffered *(ebp+0x10) "' has no member called '")
12448     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
12449     (write-buffered *(ebp+0x10) %eax)
12450     (write-buffered *(ebp+0x10) "'\n")
12451     (flush *(ebp+0x10))
12452     (stop *(ebp+0x14) 1)
12453     # never gets here
12454 
12455 $check-mu-get-stmt:error-output-not-in-register:
12456     (write-buffered *(ebp+0x10) "fn ")
12457     8b/-> *(ebp+0xc) 0/r32/eax
12458     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12459     (write-buffered *(ebp+0x10) %eax)
12460     (write-buffered *(ebp+0x10) ": stmt get: output '")
12461     (lookup *edi *(edi+4))  # Var-name Var-name => eax
12462     (write-buffered *(ebp+0x10) %eax)
12463     (write-buffered *(ebp+0x10) "' is not in a register\n")
12464     (flush *(ebp+0x10))
12465     (stop *(ebp+0x14) 1)
12466     # never gets here
12467 
12468 $check-mu-get-stmt:error-output-type-not-address:
12469     (write-buffered *(ebp+0x10) "fn ")
12470     8b/-> *(ebp+0xc) 0/r32/eax
12471     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12472     (write-buffered *(ebp+0x10) %eax)
12473     (write-buffered *(ebp+0x10) ": stmt get: output must be an address\n")
12474     (flush *(ebp+0x10))
12475     (stop *(ebp+0x14) 1)
12476     # never gets here
12477 
12478 $check-mu-get-stmt:error-bad-output-type:
12479     (write-buffered *(ebp+0x10) "fn ")
12480     8b/-> *(ebp+0xc) 0/r32/eax
12481     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12482     (write-buffered *(ebp+0x10) %eax)
12483     (write-buffered *(ebp+0x10) ": stmt get: wrong output type for member '")
12484     (write-buffered *(ebp+0x10) %ecx)
12485     (write-buffered *(ebp+0x10) "' of type '")
12486     bf/copy-to-edi Type-id/imm32
12487     (write-buffered *(ebp+0x10) *(edi+ebx<<2+0xc))
12488     (write-buffered *(ebp+0x10) "'\n")
12489     (flush *(ebp+0x10))
12490     (stop *(ebp+0x14) 1)
12491     # never gets here
12492 
12493 check-mu-index-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12494     # . prologue
12495     55/push-ebp
12496     89/<- %ebp 4/r32/esp
12497     # . save registers
12498 $check-mu-index-stmt:end:
12499     # . restore registers
12500     # . epilogue
12501     89/<- %esp 5/r32/ebp
12502     5d/pop-to-ebp
12503     c3/return
12504 
12505 check-mu-length-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12506     # . prologue
12507     55/push-ebp
12508     89/<- %ebp 4/r32/esp
12509     # . save registers
12510 $check-mu-length-stmt:end:
12511     # . restore registers
12512     # . epilogue
12513     89/<- %esp 5/r32/ebp
12514     5d/pop-to-ebp
12515     c3/return
12516 
12517 check-mu-compute-offset-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12518     # . prologue
12519     55/push-ebp
12520     89/<- %ebp 4/r32/esp
12521     # . save registers
12522 $check-mu-compute-offset-stmt:end:
12523     # . restore registers
12524     # . epilogue
12525     89/<- %esp 5/r32/ebp
12526     5d/pop-to-ebp
12527     c3/return
12528 
12529 check-mu-allocate-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12530     # . prologue
12531     55/push-ebp
12532     89/<- %ebp 4/r32/esp
12533     # . save registers
12534 $check-mu-allocate-stmt:end:
12535     # . restore registers
12536     # . epilogue
12537     89/<- %esp 5/r32/ebp
12538     5d/pop-to-ebp
12539     c3/return
12540 
12541 check-mu-populate-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12542     # . prologue
12543     55/push-ebp
12544     89/<- %ebp 4/r32/esp
12545     # . save registers
12546 $check-mu-populate-stmt:end:
12547     # . restore registers
12548     # . epilogue
12549     89/<- %esp 5/r32/ebp
12550     5d/pop-to-ebp
12551     c3/return
12552 
12553 check-mu-populate-stream-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12554     # . prologue
12555     55/push-ebp
12556     89/<- %ebp 4/r32/esp
12557     # . save registers
12558 $check-mu-populate-stream-stmt:end:
12559     # . restore registers
12560     # . epilogue
12561     89/<- %esp 5/r32/ebp
12562     5d/pop-to-ebp
12563     c3/return
12564 
12565 check-mu-read-from-stream-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12566     # . prologue
12567     55/push-ebp
12568     89/<- %ebp 4/r32/esp
12569     # . save registers
12570 $check-mu-read-from-stream-stmt:end:
12571     # . restore registers
12572     # . epilogue
12573     89/<- %esp 5/r32/ebp
12574     5d/pop-to-ebp
12575     c3/return
12576 
12577 check-mu-write-to-stream-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12578     # . prologue
12579     55/push-ebp
12580     89/<- %ebp 4/r32/esp
12581     # . save registers
12582 $check-mu-write-to-stream-stmt:end:
12583     # . restore registers
12584     # . epilogue
12585     89/<- %esp 5/r32/ebp
12586     5d/pop-to-ebp
12587     c3/return
12588 
12589 check-mu-call:  # stmt: (addr stmt), callee: (addr function), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12590     # . prologue
12591     55/push-ebp
12592     89/<- %ebp 4/r32/esp
12593     # var type-parameters: (addr table (handle array byte) (addr type-tree) 8)
12594     68/push 0/imm32
12595     # var type-parameters-storage: (table (handle array byte) (addr type-tree) 8)
12596     81 5/subop/subtract %esp 0x60/imm32
12597     68/push 0x60/imm32/size
12598     68/push 0/imm32/read
12599     68/push 0/imm32/write
12600     # save a pointer to type-parameters-storage at type-parameters
12601     89/<- *(ebp-4) 4/r32/esp
12602     (clear-stream *(ebp-4))
12603     # . save registers
12604     50/push-eax
12605     51/push-ecx
12606     52/push-edx
12607     53/push-ebx
12608     56/push-esi
12609     57/push-edi
12610     # esi = stmt
12611     8b/-> *(ebp+8) 6/r32/esi
12612     # edi = callee
12613     8b/-> *(ebp+0xc) 7/r32/edi
12614     # var inouts/ecx: (addr stmt-var) = lookup(stmt->inouts)
12615     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12616     89/<- %ecx 0/r32/eax
12617     # var expected/edx: (addr list var) = lookup(f->inouts)
12618     (lookup *(edi+8) *(edi+0xc))  # Function-inouts Function-inouts => eax
12619     89/<- %edx 0/r32/eax
12620     {
12621 $check-mu-call:check-for-inouts:
12622       # if (inouts == 0) break
12623       81 7/subop/compare %ecx 0/imm32
12624       0f 84/jump-if-= break/disp32
12625       # if (expected == 0) error
12626       81 7/subop/compare %edx 0/imm32
12627       0f 84/jump-if-= break/disp32
12628 $check-mu-call:check-inout-type:
12629       # var v/eax: (addr v) = lookup(inouts->value)
12630       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12631       # var t/ebx: (addr type-tree) = lookup(v->type)
12632       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12633       89/<- %ebx 0/r32/eax
12634       # if (inouts->is-deref?) t = t->right  # TODO: check that t->left is an addr
12635       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
12636       {
12637         74/jump-if-= break/disp8
12638         (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
12639         89/<- %ebx 0/r32/eax
12640         # if t->right is null, t = t->left
12641         81 7/subop/compare *(ebx+0xc) 0/imm32  # Type-tree-right
12642         75/jump-if-!= break/disp8
12643         (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
12644         89/<- %ebx 0/r32/eax
12645       }
12646       # var v2/eax: (addr v) = lookup(expected->value)
12647       (lookup *edx *(edx+4))  # List-value List-value => eax
12648       # var t2/eax: (addr type-tree) = lookup(v2->type)
12649       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12650       # if (t != t2) error
12651       (type-match? %eax %ebx *(ebp-4))  # => eax
12652       3d/compare-eax-and 0/imm32/false
12653       {
12654         0f 85/jump-if-!= break/disp32
12655         (write-buffered *(ebp+0x14) "fn ")
12656         8b/-> *(ebp+0x10) 0/r32/eax
12657         (lookup *eax *(eax+4))  # Function-name Function-name => eax
12658         (write-buffered *(ebp+0x14) %eax)
12659         (write-buffered *(ebp+0x14) ": call ")
12660         (lookup *edi *(edi+4))  # Function-name Function-name => eax
12661         (write-buffered *(ebp+0x14) %eax)
12662         (write-buffered *(ebp+0x14) ": type for inout '")
12663         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12664         (lookup *eax *(eax+4))  # Var-name Var-name => eax
12665         (write-buffered *(ebp+0x14) %eax)
12666         (write-buffered *(ebp+0x14) "' is not right\n")
12667         (flush *(ebp+0x14))
12668         (stop *(ebp+0x18) 1)
12669       }
12670 $check-mu-call:continue-to-next-inout:
12671       # inouts = lookup(inouts->next)
12672       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
12673       89/<- %ecx 0/r32/eax
12674       # expected = lookup(expected->next)
12675       (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
12676       89/<- %edx 0/r32/eax
12677       #
12678       e9/jump loop/disp32
12679     }
12680 $check-mu-call:check-inout-count:
12681     # if (inouts == expected) proceed
12682     39/compare %ecx 2/r32/edx
12683     {
12684       0f 84/jump-if-= break/disp32
12685       # exactly one of the two is null
12686       # if (inouts == 0) error("too many inouts")
12687       {
12688         81 7/subop/compare %ecx 0/imm32
12689         0f 84/jump-if-= break/disp32
12690         (write-buffered *(ebp+0x14) "fn ")
12691         8b/-> *(ebp+0x10) 0/r32/eax
12692         (lookup *eax *(eax+4))  # Function-name Function-name => eax
12693         (write-buffered *(ebp+0x14) %eax)
12694         (write-buffered *(ebp+0x14) ": call ")
12695         (lookup *edi *(edi+4))  # Function-name Function-name => eax
12696         (write-buffered *(ebp+0x14) %eax)
12697         (write-buffered *(ebp+0x14) ": too many inouts\n")
12698         (flush *(ebp+0x14))
12699         (stop *(ebp+0x18) 1)
12700       }
12701       # if (expected == 0) error("too few inouts")
12702       {
12703         81 7/subop/compare %edx 0/imm32
12704         0f 84/jump-if-= break/disp32
12705         (write-buffered *(ebp+0x14) "fn ")
12706         8b/-> *(ebp+0x10) 0/r32/eax
12707         (lookup *eax *(eax+4))  # Function-name Function-name => eax
12708         (write-buffered *(ebp+0x14) %eax)
12709         (write-buffered *(ebp+0x14) ": call ")
12710         (lookup *edi *(edi+4))  # Function-name Function-name => eax
12711         (write-buffered *(ebp+0x14) %eax)
12712         (write-buffered *(ebp+0x14) ": too few inouts\n")
12713         (flush *(ebp+0x14))
12714         (stop *(ebp+0x18) 1)
12715       }
12716     }
12717 $check-mu-call:check-outputs:
12718     # var outputs/ecx: (addr stmt-var) = lookup(stmt->outputs)
12719     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
12720     89/<- %ecx 0/r32/eax
12721     # var expected/edx: (addr list var) = lookup(f->outputs)
12722     (lookup *(edi+0x10) *(edi+0x14))  # Function-outputs Function-outputs => eax
12723     89/<- %edx 0/r32/eax
12724     {
12725 $check-mu-call:check-for-outputs:
12726       # if (outputs == 0) break
12727       81 7/subop/compare %ecx 0/imm32
12728       0f 84/jump-if-= break/disp32
12729       # if (expected == 0) error
12730       81 7/subop/compare %edx 0/imm32
12731       0f 84/jump-if-= break/disp32
12732 $check-mu-call:check-output-type:
12733       # var v/eax: (addr v) = lookup(outputs->value)
12734       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12735       # var t/ebx: (addr type-tree) = lookup(v->type)
12736       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12737       89/<- %ebx 0/r32/eax
12738       # if (outputs->is-deref?) t = t->right  # TODO: check that t->left is an addr
12739       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
12740       {
12741         74/jump-if-= break/disp8
12742         (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
12743         89/<- %ebx 0/r32/eax
12744       }
12745       # var v2/eax: (addr v) = lookup(expected->value)
12746       (lookup *edx *(edx+4))  # List-value List-value => eax
12747       # var t2/eax: (addr type-tree) = lookup(v2->type)
12748       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12749       # if (t != t2) error
12750       (type-match? %eax %ebx *(ebp-4))  # => eax
12751       3d/compare-eax-and 0/imm32/false
12752       {
12753         0f 85/jump-if-!= break/disp32
12754         (write-buffered *(ebp+0x14) "fn ")
12755         8b/-> *(ebp+0x10) 0/r32/eax
12756         (lookup *eax *(eax+4))  # Function-name Function-name => eax
12757         (write-buffered *(ebp+0x14) %eax)
12758         (write-buffered *(ebp+0x14) ": call ")
12759         (lookup *edi *(edi+4))  # Function-name Function-name => eax
12760         (write-buffered *(ebp+0x14) %eax)
12761         (write-buffered *(ebp+0x14) ": type for output '")
12762         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12763         (lookup *eax *(eax+4))  # Var-name Var-name => eax
12764         (write-buffered *(ebp+0x14) %eax)
12765         (write-buffered *(ebp+0x14) "' is not right\n")
12766         (flush *(ebp+0x14))
12767         (stop *(ebp+0x18) 1)
12768       }
12769 $check-mu-call:check-output-register:
12770       # var v/eax: (addr v) = lookup(outputs->value)
12771       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12772       # var r/ebx: (addr array byte) = lookup(v->register)
12773       (lookup *(eax+18) *(eax+0x1c))  # Var-register Var-register => eax
12774       89/<- %ebx 0/r32/eax
12775       # var v2/eax: (addr v) = lookup(expected->value)
12776       (lookup *edx *(edx+4))  # Stmt-var-value Stmt-var-value => eax
12777       # var r2/eax: (addr array byte) = lookup(v2->register)
12778       (lookup *(eax+18) *(eax+0x1c))  # Var-register Var-register => eax
12779       # if (r != r2) error
12780       (string-equal? %eax %ebx)  # => eax
12781       3d/compare-eax-and 0/imm32/false
12782       {
12783         0f 85/jump-if-!= break/disp32
12784         (write-buffered *(ebp+0x14) "fn ")
12785         8b/-> *(ebp+0x10) 0/r32/eax
12786         (lookup *eax *(eax+4))  # Function-name Function-name => eax
12787         (write-buffered *(ebp+0x14) %eax)
12788         (write-buffered *(ebp+0x14) ": call ")
12789         (lookup *edi *(edi+4))  # Function-name Function-name => eax
12790         (write-buffered *(ebp+0x14) %eax)
12791         (write-buffered *(ebp+0x14) ": register for output '")
12792         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
12793         (lookup *eax *(eax+4))  # Var-name Var-name => eax
12794         (write-buffered *(ebp+0x14) %eax)
12795         (write-buffered *(ebp+0x14) "' is not right\n")
12796         (flush *(ebp+0x14))
12797         (stop *(ebp+0x18) 1)
12798       }
12799 $check-mu-call:continue-to-next-output:
12800       # outputs = lookup(outputs->next)
12801       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
12802       89/<- %ecx 0/r32/eax
12803       # expected = lookup(expected->next)
12804       (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
12805       89/<- %edx 0/r32/eax
12806       #
12807       e9/jump loop/disp32
12808     }
12809 $check-mu-call:check-output-count:
12810     # if (outputs == expected) proceed
12811     39/compare %ecx 2/r32/edx
12812     {
12813       0f 84/jump-if-= break/disp32
12814       # exactly one of the two is null
12815       # if (outputs == 0) error("too many outputs")
12816       {
12817         81 7/subop/compare %ecx 0/imm32
12818         0f 84/jump-if-= break/disp32
12819         (write-buffered *(ebp+0x14) "fn ")
12820         8b/-> *(ebp+0x10) 0/r32/eax
12821         (lookup *eax *(eax+4))  # Function-name Function-name => eax
12822         (write-buffered *(ebp+0x14) %eax)
12823         (write-buffered *(ebp+0x14) ": call ")
12824         (lookup *edi *(edi+4))  # Function-name Function-name => eax
12825         (write-buffered *(ebp+0x14) %eax)
12826         (write-buffered *(ebp+0x14) ": too many outputs\n")
12827         (flush *(ebp+0x14))
12828         (stop *(ebp+0x18) 1)
12829       }
12830       # if (expected == 0) error("too few outputs")
12831       {
12832         81 7/subop/compare %edx 0/imm32
12833         0f 84/jump-if-= break/disp32
12834         (write-buffered *(ebp+0x14) "fn ")
12835         8b/-> *(ebp+0x10) 0/r32/eax
12836         (lookup *eax *(eax+4))  # Function-name Function-name => eax
12837         (write-buffered *(ebp+0x14) %eax)
12838         (write-buffered *(ebp+0x14) ": call ")
12839         (lookup *edi *(edi+4))  # Function-name Function-name => eax
12840         (write-buffered *(ebp+0x14) %eax)
12841         (write-buffered *(ebp+0x14) ": too few outputs\n")
12842         (flush *(ebp+0x14))
12843         (stop *(ebp+0x18) 1)
12844       }
12845     }
12846 $check-mu-call:end:
12847     # . restore registers
12848     5f/pop-to-edi
12849     5e/pop-to-esi
12850     5b/pop-to-ebx
12851     5a/pop-to-edx
12852     59/pop-to-ecx
12853     58/pop-to-eax
12854     # . reclaim locals exclusively on the stack
12855     81 0/subop/add %esp 0x70/imm32
12856     # . epilogue
12857     89/<- %esp 5/r32/ebp
12858     5d/pop-to-ebp
12859     c3/return
12860 
12861 # like type-equal? but takes literals into account
12862 type-match?:  # def: (addr type-tree), call: (addr type-tree), type-parameters: (addr table (handle array byte) (addr type-tree)) -> result/eax: boolean
12863     # . prologue
12864     55/push-ebp
12865     89/<- %ebp 4/r32/esp
12866     # if (call == literal) return true  # TODO: more precise
12867     (is-simple-mu-type? *(ebp+0xc) 0)  # literal => eax
12868     3d/compare-eax-and 0/imm32/false
12869     b8/copy-to-eax 1/imm32/true
12870     75/jump-if-!= $type-match?:end/disp8
12871 $type-match?:baseline:
12872     # otherwise fall back
12873     (type-component-match? *(ebp+8) *(ebp+0xc) *(ebp+0x10))  # => eax
12874 $type-match?:end:
12875     # . epilogue
12876     89/<- %esp 5/r32/ebp
12877     5d/pop-to-ebp
12878     c3/return
12879 
12880 type-component-match?:  # def: (addr type-tree), call: (addr type-tree), type-parameters: (addr table (handle array byte) (addr type-tree)) -> result/eax: boolean
12881     # . prologue
12882     55/push-ebp
12883     89/<- %ebp 4/r32/esp
12884     # . save registers
12885     51/push-ecx
12886     52/push-edx
12887     53/push-ebx
12888     # ecx = def
12889     8b/-> *(ebp+8) 1/r32/ecx
12890     # edx = call
12891     8b/-> *(ebp+0xc) 2/r32/edx
12892 $type-component-match?:compare-addr:
12893     # if (def == call) return true
12894     8b/-> %ecx 0/r32/eax  # Var-type
12895     39/compare %edx 0/r32/eax  # Var-type
12896     b8/copy-to-eax 1/imm32/true
12897     0f 84/jump-if-= $type-component-match?:end/disp32
12898     # if (def == 0) return false
12899     b8/copy-to-eax 0/imm32/false
12900     81 7/subop/compare %ecx 0/imm32  # Type-tree-is-atom
12901     0f 84/jump-if-= $type-component-match?:end/disp32
12902     # if (call == 0) return false
12903     81 7/subop/compare %edx 0/imm32  # Type-tree-is-atom
12904     0f 84/jump-if-= $type-component-match?:end/disp32
12905     # if def is a type parameter, just check in type-parameters
12906     {
12907 $type-component-match?:check-type-parameter:
12908       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
12909       74/jump-if-= break/disp8
12910       81 7/subop/compare *(ecx+4) 0xa/imm32/type-parameter  # Type-tree-value
12911       75/jump-if-!= break/disp8
12912 $type-component-match?:type-parameter:
12913       (type-parameter-match? *(ecx+8) *(ecx+0xc)  %edx  *(ebp+0x10))  # => eax
12914       e9/jump $type-component-match?:end/disp32
12915     }
12916     # if def is a list containing just a type parameter, just check in type-parameters
12917     {
12918 $type-component-match?:check-list-type-parameter:
12919       # if def is a list..
12920       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
12921       75/jump-if-!= break/disp8
12922       #   ..that's a singleton
12923       81 7/subop/compare *(ecx+0xc) 0/imm32  # Type-tree-left
12924       75/jump-if-!= break/disp8
12925       #   ..and whose head is a type parameter
12926       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
12927       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
12928       74/jump-if-= break/disp8
12929       81 7/subop/compare *(eax+4) 0xa/imm32/type-parameter  # Type-tree-value
12930       75/jump-if-!= break/disp8
12931 $type-component-match?:list-type-parameter:
12932       (type-parameter-match? *(eax+8) *(eax+0xc)  %edx  *(ebp+0x10))  # => eax
12933       e9/jump $type-component-match?:end/disp32
12934     }
12935 $type-component-match?:compare-atom-state:
12936     # if (def->is-atom? != call->is-atom?) return false
12937     8b/-> *ecx 3/r32/ebx  # Type-tree-is-atom
12938     39/compare *edx 3/r32/ebx  # Type-tree-is-atom
12939     b8/copy-to-eax 0/imm32/false
12940     0f 85/jump-if-!= $type-component-match?:end/disp32
12941     # if def->is-atom? return (def->value == call->value)
12942     {
12943 $type-component-match?:check-atom:
12944       81 7/subop/compare %ebx 0/imm32/false
12945       74/jump-if-= break/disp8
12946 $type-component-match?:is-atom:
12947       8b/-> *(ecx+4) 0/r32/eax  # Type-tree-value
12948       39/compare *(edx+4) 0/r32/eax  # Type-tree-value
12949       0f 94/set-if-= %al
12950       81 4/subop/and %eax 0xff/imm32
12951       e9/jump $type-component-match?:end/disp32
12952     }
12953 $type-component-match?:check-left:
12954     # if (!type-component-match?(def->left, call->left)) return false
12955     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
12956     89/<- %ebx 0/r32/eax
12957     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
12958     (type-component-match? %ebx %eax *(ebp+0x10))  # => eax
12959     3d/compare-eax-and 0/imm32/false
12960     74/jump-if-= $type-component-match?:end/disp8
12961 $type-component-match?:check-right:
12962     # return type-component-match?(def->right, call->right)
12963     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
12964     89/<- %ebx 0/r32/eax
12965     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
12966     (type-component-match? %ebx %eax *(ebp+0x10))  # => eax
12967 $type-component-match?:end:
12968     # . restore registers
12969     5b/pop-to-ebx
12970     5a/pop-to-edx
12971     59/pop-to-ecx
12972     # . epilogue
12973     89/<- %esp 5/r32/ebp
12974     5d/pop-to-ebp
12975     c3/return
12976 
12977 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
12978     # . prologue
12979     55/push-ebp
12980     89/<- %ebp 4/r32/esp
12981     # . save registers
12982     51/push-ecx
12983     #
12984     (get-or-insert-handle *(ebp+0x14)  *(ebp+8) *(ebp+0xc)  0xc)  # => eax
12985     # if parameter wasn't saved, save it
12986     {
12987       81 7/subop/compare *eax 0/imm32
12988       75/jump-if-!= break/disp8
12989       8b/-> *(ebp+0x10) 1/r32/ecx
12990       89/<- *eax 1/r32/ecx
12991     }
12992     #
12993     (type-equal? *(ebp+0x10) *eax)  # => eax
12994 $type-parameter-match?:end:
12995     # . restore registers
12996     59/pop-to-ecx
12997     # . epilogue
12998     89/<- %esp 5/r32/ebp
12999     5d/pop-to-ebp
13000     c3/return
13001 
13002 size-of:  # v: (addr var) -> result/eax: int
13003     # . prologue
13004     55/push-ebp
13005     89/<- %ebp 4/r32/esp
13006     # . save registers
13007     51/push-ecx
13008     # var t/ecx: (addr type-tree) = lookup(v->type)
13009     8b/-> *(ebp+8) 1/r32/ecx
13010 #?     (write-buffered Stderr "size-of ")
13011 #?     (write-int32-hex-buffered Stderr %ecx)
13012 #?     (write-buffered Stderr Newline)
13013 #?     (write-buffered Stderr "type allocid: ")
13014 #?     (write-int32-hex-buffered Stderr *(ecx+8))
13015 #?     (write-buffered Stderr Newline)
13016 #?     (flush Stderr)
13017     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
13018     89/<- %ecx 0/r32/eax
13019     # if is-mu-array?(t) return size-of-array(t)
13020     {
13021       (is-mu-array? %ecx)  # => eax
13022       3d/compare-eax-and 0/imm32/false
13023       74/jump-if-= break/disp8
13024       (size-of-array %ecx)  # => eax
13025       eb/jump $size-of:end/disp8
13026     }
13027     # if is-mu-stream?(t) return size-of-stream(t)
13028     {
13029       (is-mu-stream? %ecx)  # => eax
13030       3d/compare-eax-and 0/imm32/false
13031       74/jump-if-= break/disp8
13032       (size-of-stream %ecx)  # => eax
13033       eb/jump $size-of:end/disp8
13034     }
13035     # if (!t->is-atom?) t = lookup(t->left)
13036     {
13037       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
13038       75/jump-if-!= break/disp8
13039       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
13040       89/<- %ecx 0/r32/eax
13041     }
13042     # TODO: assert t->is-atom?
13043     (size-of-type-id *(ecx+4))  # Type-tree-value => eax
13044 $size-of: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-deref:  # v: (addr var) -> result/eax: int
13053     # . prologue
13054     55/push-ebp
13055     89/<- %ebp 4/r32/esp
13056     # . save registers
13057     51/push-ecx
13058     # var t/ecx: (addr type-tree) = lookup(v->type)
13059     8b/-> *(ebp+8) 1/r32/ecx
13060     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
13061     89/<- %ecx 0/r32/eax
13062     # TODO: assert(t is an addr)
13063     # t = lookup(t->right)
13064     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
13065     89/<- %ecx 0/r32/eax
13066     # if is-mu-array?(t) return size-of-array(t)
13067     {
13068       (is-mu-array? %ecx)  # => eax
13069       3d/compare-eax-and 0/imm32/false
13070       74/jump-if-= break/disp8
13071       (size-of-array %ecx)  # => eax
13072       eb/jump $size-of-deref:end/disp8
13073     }
13074     # if is-mu-stream?(t) return size-of-stream(t)
13075     {
13076       (is-mu-stream? %ecx)  # => eax
13077       3d/compare-eax-and 0/imm32/false
13078       74/jump-if-= break/disp8
13079       (size-of-stream %ecx)  # => eax
13080       eb/jump $size-of-deref:end/disp8
13081     }
13082     # if (!t->is-atom?) t = lookup(t->left)
13083     {
13084       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
13085       75/jump-if-!= break/disp8
13086       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
13087       89/<- %ecx 0/r32/eax
13088     }
13089     # TODO: assert t->is-atom?
13090     (size-of-type-id *(ecx+4))  # Type-tree-value => eax
13091 $size-of-deref:end:
13092     # . restore registers
13093     59/pop-to-ecx
13094     # . epilogue
13095     89/<- %esp 5/r32/ebp
13096     5d/pop-to-ebp
13097     c3/return
13098 
13099 is-mu-array?:  # t: (addr type-tree) -> result/eax: boolean
13100     # . prologue
13101     55/push-ebp
13102     89/<- %ebp 4/r32/esp
13103     # . save registers
13104     51/push-ecx
13105     # ecx = t
13106     8b/-> *(ebp+8) 1/r32/ecx
13107     # if t->is-atom?, return false
13108     81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
13109     75/jump-if-!= $is-mu-array?:return-false/disp8
13110     # if !t->left->is-atom?, return false
13111     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
13112     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
13113     74/jump-if-= $is-mu-array?:return-false/disp8
13114     # return t->left->value == array
13115     81 7/subop/compare *(eax+4) 3/imm32/array-type-id  # Type-tree-value
13116     0f 94/set-if-= %al
13117     81 4/subop/and %eax 0xff/imm32
13118     eb/jump $is-mu-array?:end/disp8
13119 $is-mu-array?:return-false:
13120     b8/copy-to-eax 0/imm32/false
13121 $is-mu-array?:end:
13122     # . restore registers
13123     59/pop-to-ecx
13124     # . epilogue
13125     89/<- %esp 5/r32/ebp
13126     5d/pop-to-ebp
13127     c3/return
13128 
13129 # size of a statically allocated array where the size is part of the type expression
13130 size-of-array:  # a: (addr type-tree) -> result/eax: int
13131     # . prologue
13132     55/push-ebp
13133     89/<- %ebp 4/r32/esp
13134     # . save registers
13135     51/push-ecx
13136     52/push-edx
13137     #
13138     8b/-> *(ebp+8) 1/r32/ecx
13139     # TODO: assert that a->left is 'array'
13140     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
13141     89/<- %ecx 0/r32/eax
13142     # var elem-type/edx: type-id = a->right->left->value
13143     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
13144     8b/-> *(eax+4) 2/r32/edx  # Type-tree-value
13145     # TODO: assert that a->right->right->left->value == size
13146     # var array-size/ecx: int = a->right->right->left->value-size
13147     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
13148     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
13149     8b/-> *(eax+8) 1/r32/ecx  # Type-tree-value-size
13150     # return 4 + array-size * size-of(elem-type)
13151     (size-of-type-id-as-array-element %edx)  # => eax
13152     f7 4/subop/multiply-into-eax %ecx
13153     05/add-to-eax 4/imm32  # for array size
13154 $size-of-array:end:
13155     # . restore registers
13156     5a/pop-to-edx
13157     59/pop-to-ecx
13158     # . epilogue
13159     89/<- %esp 5/r32/ebp
13160     5d/pop-to-ebp
13161     c3/return
13162 
13163 is-mu-stream?:  # t: (addr type-tree) -> result/eax: boolean
13164     # . prologue
13165     55/push-ebp
13166     89/<- %ebp 4/r32/esp
13167     # . save registers
13168     51/push-ecx
13169     # ecx = t
13170     8b/-> *(ebp+8) 1/r32/ecx
13171     # if t->is-atom?, return false
13172     81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
13173     75/jump-if-!= $is-mu-stream?:return-false/disp8
13174     # if !t->left->is-atom?, return false
13175     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
13176     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
13177     74/jump-if-= $is-mu-stream?:return-false/disp8
13178     # return t->left->value == stream
13179     81 7/subop/compare *(eax+4) 0xb/imm32/stream-type-id  # Type-tree-value
13180     0f 94/set-if-= %al
13181     81 4/subop/and %eax 0xff/imm32
13182     eb/jump $is-mu-stream?:end/disp8
13183 $is-mu-stream?:return-false:
13184     b8/copy-to-eax 0/imm32/false
13185 $is-mu-stream?:end:
13186     # . restore registers
13187     59/pop-to-ecx
13188     # . epilogue
13189     89/<- %esp 5/r32/ebp
13190     5d/pop-to-ebp
13191     c3/return
13192 
13193 # size of a statically allocated stream where the size is part of the type expression
13194 size-of-stream:  # a: (addr type-tree) -> result/eax: int
13195     # . prologue
13196     55/push-ebp
13197     89/<- %ebp 4/r32/esp
13198     #
13199     (size-of-array *(ebp+8))  # assumes we ignore the actual type name 'array' in the type
13200     05/add-to-eax 8/imm32  # for read/write pointers
13201 $size-of-stream:end:
13202     # . epilogue
13203     89/<- %esp 5/r32/ebp
13204     5d/pop-to-ebp
13205     c3/return
13206 
13207 size-of-type-id:  # t: type-id -> result/eax: int
13208     # . prologue
13209     55/push-ebp
13210     89/<- %ebp 4/r32/esp
13211     # . save registers
13212     51/push-ecx
13213     # var out/ecx: (handle typeinfo)
13214     68/push 0/imm32
13215     68/push 0/imm32
13216     89/<- %ecx 4/r32/esp
13217     # eax = t
13218     8b/-> *(ebp+8) 0/r32/eax
13219     # if t is a literal, return 0
13220     3d/compare-eax-and 0/imm32
13221     0f 84/jump-if-= $size-of-type-id:end/disp32  # eax changes type from type-id to int
13222     # if t is a byte, return 4 (because we don't really support non-multiples of 4)
13223     3d/compare-eax-and 8/imm32/byte
13224     {
13225       75/jump-if-!= break/disp8
13226       b8/copy-to-eax 4/imm32
13227       eb/jump $size-of-type-id:end/disp8
13228     }
13229     # if t is a handle, return 8
13230     3d/compare-eax-and 4/imm32/handle
13231     {
13232       75/jump-if-!= break/disp8
13233       b8/copy-to-eax 8/imm32
13234       eb/jump $size-of-type-id:end/disp8  # eax changes type from type-id to int
13235     }
13236     # if t is a user-defined type, return its size
13237     # TODO: support non-atom type
13238     (find-typeinfo %eax %ecx)
13239     {
13240       81 7/subop/compare *ecx 0/imm32
13241       74/jump-if-= break/disp8
13242 $size-of-type-id:user-defined:
13243       (lookup *ecx *(ecx+4))  # => eax
13244       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
13245       eb/jump $size-of-type-id:end/disp8
13246     }
13247     # otherwise return the word size
13248     b8/copy-to-eax 4/imm32
13249 $size-of-type-id:end:
13250     # . reclaim locals
13251     81 0/subop/add %esp 8/imm32
13252     # . restore registers
13253     59/pop-to-ecx
13254     # . epilogue
13255     89/<- %esp 5/r32/ebp
13256     5d/pop-to-ebp
13257     c3/return
13258 
13259 type-equal?:  # a: (addr type-tree), b: (addr type-tree) -> result/eax: boolean
13260     # . prologue
13261     55/push-ebp
13262     89/<- %ebp 4/r32/esp
13263     # . save registers
13264     51/push-ecx
13265     52/push-edx
13266     53/push-ebx
13267     # ecx = a
13268     8b/-> *(ebp+8) 1/r32/ecx
13269     # edx = b
13270     8b/-> *(ebp+0xc) 2/r32/edx
13271 $type-equal?:compare-addr:
13272     # if (a == b) return true
13273     8b/-> %ecx 0/r32/eax  # Var-type
13274     39/compare %edx 0/r32/eax  # Var-type
13275     b8/copy-to-eax 1/imm32/true
13276     0f 84/jump-if-= $type-equal?:end/disp32
13277 $type-equal?:compare-atom-state:
13278     # if (a->is-atom? != b->is-atom?) return false
13279     8b/-> *ecx 3/r32/ebx  # Type-tree-is-atom
13280     39/compare *edx 3/r32/ebx  # Type-tree-is-atom
13281     b8/copy-to-eax 0/imm32/false
13282     0f 85/jump-if-!= $type-equal?:end/disp32
13283     # if a->is-atom? return (a->value == b->value)
13284     {
13285 $type-equal?:check-atom:
13286       81 7/subop/compare %ebx 0/imm32/false
13287       74/jump-if-= break/disp8
13288 $type-equal?:is-atom:
13289       8b/-> *(ecx+4) 0/r32/eax  # Type-tree-value
13290       39/compare *(edx+4) 0/r32/eax  # Type-tree-value
13291       0f 94/set-if-= %al
13292       81 4/subop/and %eax 0xff/imm32
13293       e9/jump $type-equal?:end/disp32
13294     }
13295 $type-equal?:check-left:
13296     # if (!type-equal?(a->left, b->left)) return false
13297     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
13298     89/<- %ebx 0/r32/eax
13299     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
13300     (type-equal? %eax %ebx)  # => eax
13301     3d/compare-eax-and 0/imm32/false
13302     74/jump-if-= $type-equal?:end/disp8
13303 $type-equal?:check-right:
13304     # return type-equal?(a->right, b->right)
13305     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
13306     89/<- %ebx 0/r32/eax
13307     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
13308     (type-equal? %eax %ebx)  # => eax
13309 $type-equal?:end:
13310     # . restore registers
13311     5b/pop-to-ebx
13312     5a/pop-to-edx
13313     59/pop-to-ecx
13314     # . epilogue
13315     89/<- %esp 5/r32/ebp
13316     5d/pop-to-ebp
13317     c3/return
13318 
13319 #######################################################
13320 # Code-generation
13321 #######################################################
13322 
13323 == data
13324 
13325 # Global state added to each var record when performing code-generation.
13326 Curr-local-stack-offset:  # (addr int)
13327     0/imm32
13328 
13329 == code
13330 
13331 emit-subx:  # out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
13332     # . prologue
13333     55/push-ebp
13334     89/<- %ebp 4/r32/esp
13335     # . save registers
13336     50/push-eax
13337     # var curr/eax: (addr function) = *Program->functions
13338     (lookup *_Program-functions *_Program-functions->payload)  # => eax
13339     {
13340       # if (curr == null) break
13341       3d/compare-eax-and 0/imm32
13342       0f 84/jump-if-= break/disp32
13343       (emit-subx-function *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))
13344       # curr = lookup(curr->next)
13345       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
13346       e9/jump loop/disp32
13347     }
13348 $emit-subx:end:
13349     # . restore registers
13350     58/pop-to-eax
13351     # . epilogue
13352     89/<- %esp 5/r32/ebp
13353     5d/pop-to-ebp
13354     c3/return
13355 
13356 emit-subx-function:  # out: (addr buffered-file), f: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13357     # . prologue
13358     55/push-ebp
13359     89/<- %ebp 4/r32/esp
13360     # some preprocessing
13361     (populate-mu-type-offsets-in-inouts *(ebp+0xc))
13362     # . save registers
13363     50/push-eax
13364     51/push-ecx
13365     52/push-edx
13366     # initialize some global state
13367     c7 0/subop/copy *Curr-block-depth 1/imm32  # Important: keep this in sync with the parse phase
13368     c7 0/subop/copy *Curr-local-stack-offset 0/imm32
13369     # ecx = f
13370     8b/-> *(ebp+0xc) 1/r32/ecx
13371     # var vars/edx: (stack (addr var) 256)
13372     81 5/subop/subtract %esp 0xc00/imm32
13373     68/push 0xc00/imm32/size
13374     68/push 0/imm32/top
13375     89/<- %edx 4/r32/esp
13376     # var name/eax: (addr array byte) = lookup(f->name)
13377     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
13378     #
13379     (write-buffered *(ebp+8) %eax)
13380     (write-buffered *(ebp+8) ":\n")
13381     (emit-subx-prologue *(ebp+8))
13382     # var body/eax: (addr block) = lookup(f->body)
13383     (lookup *(ecx+0x18) *(ecx+0x1c))  # Function-body Function-body => eax
13384     #
13385     (emit-subx-block *(ebp+8) %eax %edx *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13386     (emit-subx-epilogue *(ebp+8))
13387     # TODO: validate that *Curr-block-depth and *Curr-local-stack-offset have
13388     # been cleaned up
13389 $emit-subx-function:end:
13390     # . reclaim locals
13391     81 0/subop/add %esp 0xc08/imm32
13392     # . restore registers
13393     5a/pop-to-edx
13394     59/pop-to-ecx
13395     58/pop-to-eax
13396     # . epilogue
13397     89/<- %esp 5/r32/ebp
13398     5d/pop-to-ebp
13399     c3/return
13400 
13401 populate-mu-type-offsets-in-inouts:  # f: (addr function)
13402     # . prologue
13403     55/push-ebp
13404     89/<- %ebp 4/r32/esp
13405     # . save registers
13406     50/push-eax
13407     51/push-ecx
13408     52/push-edx
13409     53/push-ebx
13410     57/push-edi
13411     # var next-offset/edx: int = 8
13412     ba/copy-to-edx 8/imm32
13413     # var curr/ecx: (addr list var) = lookup(f->inouts)
13414     8b/-> *(ebp+8) 1/r32/ecx
13415     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
13416     89/<- %ecx 0/r32/eax
13417     {
13418 $populate-mu-type-offsets-in-inouts:loop:
13419       81 7/subop/compare %ecx 0/imm32
13420       74/jump-if-= break/disp8
13421       # var v/ebx: (addr var) = lookup(curr->value)
13422       (lookup *ecx *(ecx+4))  # List-value List-value => eax
13423       89/<- %ebx 0/r32/eax
13424 #?       (lookup *ebx *(ebx+4))
13425 #?       (write-buffered Stderr "setting offset of fn inout ")
13426 #?       (write-buffered Stderr %eax)
13427 #?       (write-buffered Stderr "@")
13428 #?       (write-int32-hex-buffered Stderr %ebx)
13429 #?       (write-buffered Stderr " to ")
13430 #?       (write-int32-hex-buffered Stderr %edx)
13431 #?       (write-buffered Stderr Newline)
13432 #?       (flush Stderr)
13433       # v->offset = next-offset
13434       89/<- *(ebx+0x14) 2/r32/edx  # Var-offset
13435       # next-offset += size-of(v)
13436       (size-of %ebx)  # => eax
13437       01/add-to %edx 0/r32/eax
13438       # curr = lookup(curr->next)
13439       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
13440       89/<- %ecx 0/r32/eax
13441       #
13442       eb/jump loop/disp8
13443     }
13444 $populate-mu-type-offsets-in-inouts:end:
13445     # . restore registers
13446     5f/pop-to-edi
13447     5b/pop-to-ebx
13448     5a/pop-to-edx
13449     59/pop-to-ecx
13450     58/pop-to-eax
13451     # . epilogue
13452     89/<- %esp 5/r32/ebp
13453     5d/pop-to-ebp
13454     c3/return
13455 
13456 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)
13457     # . prologue
13458     55/push-ebp
13459     89/<- %ebp 4/r32/esp
13460     # . save registers
13461     50/push-eax
13462     51/push-ecx
13463     53/push-ebx
13464     56/push-esi
13465     # esi = stmts
13466     8b/-> *(ebp+0xc) 6/r32/esi
13467     #
13468     {
13469 $emit-subx-stmt-list:loop:
13470       81 7/subop/compare %esi 0/imm32
13471       0f 84/jump-if-= break/disp32
13472       # var curr-stmt/ecx: (addr stmt) = lookup(stmts->value)
13473       (lookup *esi *(esi+4))  # List-value List-value => eax
13474       89/<- %ecx 0/r32/eax
13475       {
13476 $emit-subx-stmt-list:check-for-block:
13477         81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
13478         75/jump-if-!= break/disp8
13479 $emit-subx-stmt-list:block:
13480         (emit-subx-block *(ebp+8) %ecx *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
13481       }
13482       {
13483 $emit-subx-stmt-list:check-for-stmt:
13484         81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
13485         0f 85/jump-if-!= break/disp32
13486 $emit-subx-stmt-list:stmt1:
13487         {
13488           (is-mu-branch? %ecx)  # => eax
13489           3d/compare-eax-and 0/imm32/false
13490           0f 84/jump-if-= break/disp32
13491 $emit-subx-stmt-list:branch-stmt:
13492 +-- 27 lines: # unconditional loops -----------------------------------------------------------------------------------------------------------------------------------------------------
13519 +-- 16 lines: # unconditional breaks ----------------------------------------------------------------------------------------------------------------------------------------------------
13535 +-- 38 lines: # simple conditional branches without a target ----------------------------------------------------------------------------------------------------------------------------
13573 +-- 19 lines: # conditional branches with an explicit target ----------------------------------------------------------------------------------------------------------------------------
13592         }
13593 $emit-subx-stmt-list:1-to-1:
13594         (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x18) *(ebp+0x1c))
13595         e9/jump $emit-subx-stmt-list:continue/disp32
13596       }
13597       {
13598 $emit-subx-stmt-list:check-for-var-def:
13599         81 7/subop/compare *ecx 2/imm32/var-def  # Stmt-tag
13600         75/jump-if-!= break/disp8
13601 $emit-subx-stmt-list:var-def:
13602         (emit-subx-var-def *(ebp+8) %ecx)
13603         (push *(ebp+0x10) *(ecx+4))  # Vardef-var
13604         (push *(ebp+0x10) *(ecx+8))  # Vardef-var
13605         (push *(ebp+0x10) 0)  # Live-var-register-spilled = 0 for vars on the stack
13606         #
13607         eb/jump $emit-subx-stmt-list:continue/disp8
13608       }
13609       {
13610 $emit-subx-stmt-list:check-for-reg-var-def:
13611         81 7/subop/compare *ecx 3/imm32/reg-var-def  # Stmt-tag
13612         0f 85/jump-if-!= break/disp32
13613 $emit-subx-stmt-list:reg-var-def:
13614         # TODO: ensure that there's exactly one output
13615         (push-output-and-maybe-emit-spill *(ebp+8) %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
13616         # emit the instruction as usual
13617         (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x18) *(ebp+0x1c))
13618         #
13619         eb/jump $emit-subx-stmt-list:continue/disp8
13620       }
13621 $emit-subx-stmt-list:continue:
13622       # TODO: raise an error on unrecognized Stmt-tag
13623       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
13624       89/<- %esi 0/r32/eax
13625       e9/jump loop/disp32
13626     }
13627 $emit-subx-stmt-list:emit-cleanup:
13628     (emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth)
13629 $emit-subx-stmt-list:clean-up:
13630     (clean-up-blocks *(ebp+0x10) *Curr-block-depth *(ebp+0x14))
13631 $emit-subx-stmt-list:end:
13632     # . restore registers
13633     5e/pop-to-esi
13634     5b/pop-to-ebx
13635     59/pop-to-ecx
13636     58/pop-to-eax
13637     # . epilogue
13638     89/<- %esp 5/r32/ebp
13639     5d/pop-to-ebp
13640     c3/return
13641 
13642 # 'later-stmts' includes 'stmt', but will behave the same even without it; reg-var-def stmts are guaranteed not to write to function outputs.
13643 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)
13644     # . prologue
13645     55/push-ebp
13646     89/<- %ebp 4/r32/esp
13647     # . save registers
13648     50/push-eax
13649     51/push-ecx
13650     52/push-edx
13651     # ecx = stmt
13652     8b/-> *(ebp+0xc) 1/r32/ecx
13653     # var sv/eax: (addr stmt-var) = lookup(curr-stmt->outputs)
13654     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
13655     # TODO: assert !sv->is-deref?
13656     # var v/ecx: (addr var) = lookup(sv->value)
13657     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13658     89/<- %ecx 0/r32/eax
13659     # v->block-depth = *Curr-block-depth
13660     8b/-> *Curr-block-depth 0/r32/eax
13661     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
13662 #?     (write-buffered Stderr "var ")
13663 #?     (lookup *ecx *(ecx+4))
13664 #?     (write-buffered Stderr %eax)
13665 #?     (write-buffered Stderr " at depth ")
13666 #?     (write-int32-hex-buffered Stderr *(ecx+0x10))
13667 #?     (write-buffered Stderr Newline)
13668 #?     (flush Stderr)
13669     # ensure that v is in a register
13670     81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
13671     0f 84/jump-if-= $push-output-and-maybe-emit-spill:abort/disp32
13672     # var emit-spill?/edx: boolean = not-yet-spilled-this-block? && will-not-write-some-register?(fn)
13673     (not-yet-spilled-this-block? %ecx *(ebp+0x10))  # => eax
13674     89/<- %edx 0/r32/eax
13675     3d/compare-eax-and 0/imm32/false
13676     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
13677     (will-not-write-some-register? %ecx *(ebp+0x14) *(ebp+0x18))  # => eax
13678     89/<- %edx 0/r32/eax
13679     # check emit-spill?
13680     3d/compare-eax-and 0/imm32/false
13681     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
13682     # TODO: assert(size-of(output) == 4)
13683     # *Curr-local-stack-offset -= 4
13684     81 5/subop/subtract *Curr-local-stack-offset 4/imm32
13685     # emit spill
13686     (emit-indent *(ebp+8) *Curr-block-depth)
13687     (write-buffered *(ebp+8) "ff 6/subop/push %")
13688     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
13689     (write-buffered *(ebp+8) %eax)
13690     (write-buffered *(ebp+8) Newline)
13691 $push-output-and-maybe-emit-spill:push:
13692     8b/-> *(ebp+0xc) 1/r32/ecx
13693     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
13694     # push(vars, {sv->value, emit-spill?})
13695     (push *(ebp+0x10) *eax)  # Stmt-var-value
13696     (push *(ebp+0x10) *(eax+4))  # Stmt-var-value
13697     (push *(ebp+0x10) %edx)
13698 $push-output-and-maybe-emit-spill:end:
13699     # . restore registers
13700     5a/pop-to-edx
13701     59/pop-to-ecx
13702     58/pop-to-eax
13703     # . epilogue
13704     89/<- %esp 5/r32/ebp
13705     5d/pop-to-ebp
13706     c3/return
13707 
13708 $push-output-and-maybe-emit-spill:abort:
13709     # error("var '" var->name "' initialized from an instruction must live in a register\n")
13710     (write-buffered *(ebp+0x1c) "var '")
13711     (write-buffered *(ebp+0x1c) *eax)  # Var-name
13712     (write-buffered *(ebp+0x1c) "' initialized from an instruction must live in a register\n")
13713     (flush *(ebp+0x1c))
13714     (stop *(ebp+0x20) 1)
13715     # never gets here
13716 
13717 emit-subx-cleanup-and-unconditional-nonlocal-branch:  # out: (addr buffered-file), stmt: (addr stmt1), vars: (addr stack live-var)
13718     # . prologue
13719     55/push-ebp
13720     89/<- %ebp 4/r32/esp
13721     # . save registers
13722     50/push-eax
13723     51/push-ecx
13724     # ecx = stmt
13725     8b/-> *(ebp+0xc) 1/r32/ecx
13726     # var target/eax: (addr array byte) = curr-stmt->inouts->value->name
13727     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13728     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13729     (lookup *eax *(eax+4))  # Var-name Var-name => eax
13730     # clean up until target block
13731     (emit-cleanup-code-until-target *(ebp+8) *(ebp+0x10) %eax)
13732     # emit jump to target block
13733     (emit-indent *(ebp+8) *Curr-block-depth)
13734     (write-buffered *(ebp+8) "e9/jump ")
13735     (write-buffered *(ebp+8) %eax)
13736     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
13737     (string-starts-with? %eax "break")
13738     3d/compare-eax-and 0/imm32/false
13739     {
13740       74/jump-if-= break/disp8
13741       (write-buffered *(ebp+8) ":break/disp32\n")
13742     }
13743     3d/compare-eax-and 0/imm32/false  # just in case the function call modified flags
13744     {
13745       75/jump-if-!= break/disp8
13746       (write-buffered *(ebp+8) ":loop/disp32\n")
13747     }
13748 $emit-subx-cleanup-and-unconditional-nonlocal-branch:end:
13749     # . restore registers
13750     59/pop-to-ecx
13751     58/pop-to-eax
13752     # . epilogue
13753     89/<- %esp 5/r32/ebp
13754     5d/pop-to-ebp
13755     c3/return
13756 
13757 is-mu-branch?:  # stmt: (addr stmt1) -> result/eax: boolean
13758     # . prologue
13759     55/push-ebp
13760     89/<- %ebp 4/r32/esp
13761     # . save registers
13762     51/push-ecx
13763     # ecx = lookup(stmt->operation)
13764     8b/-> *(ebp+8) 1/r32/ecx
13765     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
13766     89/<- %ecx 0/r32/eax
13767     # if (stmt->operation starts with "loop") return true
13768     (string-starts-with? %ecx "loop")  # => eax
13769     3d/compare-eax-and 0/imm32/false
13770     75/jump-if-not-equal $is-mu-branch?:end/disp8
13771     # otherwise return (stmt->operation starts with "break")
13772     (string-starts-with? %ecx "break")  # => eax
13773 $is-mu-branch?:end:
13774     # . restore registers
13775     59/pop-to-ecx
13776     # . epilogue
13777     89/<- %esp 5/r32/ebp
13778     5d/pop-to-ebp
13779     c3/return
13780 
13781 emit-reverse-break:  # out: (addr buffered-file), stmt: (addr stmt1)
13782     # . prologue
13783     55/push-ebp
13784     89/<- %ebp 4/r32/esp
13785     # . save registers
13786     50/push-eax
13787     # eax = stmt
13788     8b/-> *(ebp+0xc) 0/r32/eax
13789     #
13790     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
13791     (get Reverse-branch %eax 0x10 "reverse-branch: ")  # => eax: (addr handle array byte)
13792     (emit-indent *(ebp+8) *Curr-block-depth)
13793     (lookup *eax *(eax+4))  # => eax
13794     (write-buffered *(ebp+8) %eax)
13795     (write-buffered *(ebp+8) " break/disp32\n")
13796 $emit-reverse-break:end:
13797     # . restore registers
13798     58/pop-to-eax
13799     # . epilogue
13800     89/<- %esp 5/r32/ebp
13801     5d/pop-to-ebp
13802     c3/return
13803 
13804 == data
13805 
13806 # Table from Mu branch instructions to the reverse SubX opcodes for them.
13807 Reverse-branch:  # (table (handle array byte) (handle array byte))
13808   # a table is a stream
13809   0x140/imm32/write
13810   0/imm32/read
13811   0x140/imm32/size
13812   # data
13813   0x11/imm32/alloc-id   _string-break-if-=/imm32                0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
13814   0x11/imm32/alloc-id   _string-loop-if-=/imm32                 0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
13815   0x11/imm32/alloc-id   _string-break-if-!=/imm32               0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
13816   0x11/imm32/alloc-id   _string-loop-if-!=/imm32                0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
13817   0x11/imm32/alloc-id   _string-break-if-</imm32                0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
13818   0x11/imm32/alloc-id   _string-loop-if-</imm32                 0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
13819   0x11/imm32/alloc-id   _string-break-if->/imm32                0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
13820   0x11/imm32/alloc-id   _string-loop-if->/imm32                 0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
13821   0x11/imm32/alloc-id   _string-break-if-<=/imm32               0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
13822   0x11/imm32/alloc-id   _string-loop-if-<=/imm32                0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
13823   0x11/imm32/alloc-id   _string-break-if->=/imm32               0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
13824   0x11/imm32/alloc-id   _string-loop-if->=/imm32                0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
13825   0x11/imm32/alloc-id   _string-break-if-addr</imm32            0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
13826   0x11/imm32/alloc-id   _string-loop-if-addr</imm32             0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
13827   0x11/imm32/alloc-id   _string-break-if-addr>/imm32            0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
13828   0x11/imm32/alloc-id   _string-loop-if-addr>/imm32             0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
13829   0x11/imm32/alloc-id   _string-break-if-addr<=/imm32           0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
13830   0x11/imm32/alloc-id   _string-loop-if-addr<=/imm32            0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
13831   0x11/imm32/alloc-id   _string-break-if-addr>=/imm32           0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
13832   0x11/imm32/alloc-id   _string-loop-if-addr>=/imm32            0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
13833 
13834 == code
13835 
13836 emit-unconditional-jump-to-depth:  # out: (addr buffered-file), vars: (addr stack live-var), depth: int, label-suffix: (addr array byte)
13837     # . prologue
13838     55/push-ebp
13839     89/<- %ebp 4/r32/esp
13840     # . save registers
13841     50/push-eax
13842     51/push-ecx
13843     52/push-edx
13844     53/push-ebx
13845     56/push-esi
13846     # ecx = vars
13847     8b/-> *(ebp+0xc) 1/r32/ecx
13848     # var eax: int = vars->top
13849     8b/-> *ecx 0/r32/eax
13850     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
13851     8d/copy-address *(ecx+eax-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
13852     # var min/ecx: (addr handle var) = vars->data
13853     8d/copy-address *(ecx+8) 1/r32/ecx
13854     # edx = depth
13855     8b/-> *(ebp+0x10) 2/r32/edx
13856     {
13857 $emit-unconditional-jump-to-depth:loop:
13858       # if (curr < min) break
13859       39/compare %esi 1/r32/ecx
13860       0f 82/jump-if-addr< break/disp32
13861       # var v/ebx: (addr var) = lookup(*curr)
13862       (lookup *esi *(esi+4))  # => eax
13863       89/<- %ebx 0/r32/eax
13864       # if (v->block-depth < until-block-depth) break
13865       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
13866       0f 8c/jump-if-< break/disp32
13867       {
13868 $emit-unconditional-jump-to-depth:check:
13869         # if v->block-depth != until-block-depth, continue
13870         39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
13871         0f 85/jump-if-!= break/disp32
13872 $emit-unconditional-jump-to-depth:depth-found:
13873         # if v is not a literal, continue
13874         (size-of %ebx)  # => eax
13875         3d/compare-eax-and 0/imm32
13876         0f 85/jump-if-!= break/disp32
13877 $emit-unconditional-jump-to-depth:label-found:
13878         # emit unconditional jump, then return
13879         (emit-indent *(ebp+8) *Curr-block-depth)
13880         (write-buffered *(ebp+8) "e9/jump ")
13881         (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
13882         (write-buffered *(ebp+8) %eax)
13883         (write-buffered *(ebp+8) ":")
13884         (write-buffered *(ebp+8) *(ebp+0x14))
13885         (write-buffered *(ebp+8) "/disp32\n")
13886         eb/jump $emit-unconditional-jump-to-depth:end/disp8
13887       }
13888       # curr -= 12
13889       81 5/subop/subtract %esi 0xc/imm32
13890       e9/jump loop/disp32
13891     }
13892     # TODO: error if no label at 'depth' was found
13893 $emit-unconditional-jump-to-depth:end:
13894     # . restore registers
13895     5e/pop-to-esi
13896     5b/pop-to-ebx
13897     5a/pop-to-edx
13898     59/pop-to-ecx
13899     58/pop-to-eax
13900     # . epilogue
13901     89/<- %esp 5/r32/ebp
13902     5d/pop-to-ebp
13903     c3/return
13904 
13905 # emit clean-up code for 'vars' until some block depth
13906 # doesn't actually modify 'vars' so we need traverse manually inside the stack
13907 emit-cleanup-code-until-depth:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-depth: int
13908     # . prologue
13909     55/push-ebp
13910     89/<- %ebp 4/r32/esp
13911     # . save registers
13912     50/push-eax
13913     51/push-ecx
13914     52/push-edx
13915     53/push-ebx
13916     56/push-esi
13917 #?     (write-buffered Stderr "--- cleanup\n")
13918 #?     (flush Stderr)
13919     # ecx = vars
13920     8b/-> *(ebp+0xc) 1/r32/ecx
13921     # var esi: int = vars->top
13922     8b/-> *ecx 6/r32/esi
13923     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
13924     8d/copy-address *(ecx+esi-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
13925     # var min/ecx: (addr handle var) = vars->data
13926     81 0/subop/add %ecx 8/imm32
13927     # edx = until-block-depth
13928     8b/-> *(ebp+0x10) 2/r32/edx
13929     {
13930 $emit-cleanup-code-until-depth:loop:
13931       # if (curr < min) break
13932       39/compare %esi 1/r32/ecx
13933       0f 82/jump-if-addr< break/disp32
13934       # var v/ebx: (addr var) = lookup(*curr)
13935       (lookup *esi *(esi+4))  # => eax
13936       89/<- %ebx 0/r32/eax
13937 #?       (lookup *ebx *(ebx+4))  # Var-name
13938 #?       (write-buffered Stderr "var ")
13939 #?       (write-buffered Stderr %eax)
13940 #?       (write-buffered Stderr Newline)
13941 #?       (flush Stderr)
13942       # if (v->block-depth < until-block-depth) break
13943       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
13944       0f 8c/jump-if-< break/disp32
13945       # if v is in a register
13946       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
13947       {
13948         0f 84/jump-if-= break/disp32
13949         {
13950 $emit-cleanup-code-until-depth:check-for-previous-spill:
13951           8b/-> *(esi+8) 0/r32/eax  # Live-var-register-spilled
13952           3d/compare-eax-and 0/imm32/false
13953           74/jump-if-= break/disp8
13954 $emit-cleanup-code-until-depth:reclaim-var-in-register:
13955           (emit-indent *(ebp+8) *Curr-block-depth)
13956           (write-buffered *(ebp+8) "8f 0/subop/pop %")
13957           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
13958           (write-buffered *(ebp+8) %eax)
13959           (write-buffered *(ebp+8) Newline)
13960         }
13961         eb/jump $emit-cleanup-code-until-depth:continue/disp8
13962       }
13963       # otherwise v is on the stack
13964       {
13965         75/jump-if-!= break/disp8
13966 $emit-cleanup-code-until-depth:var-on-stack:
13967         (size-of %ebx)  # => eax
13968         # don't emit code for labels
13969         3d/compare-eax-and 0/imm32
13970         74/jump-if-= break/disp8
13971 $emit-cleanup-code-until-depth:reclaim-var-on-stack:
13972         (emit-indent *(ebp+8) *Curr-block-depth)
13973         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
13974         (write-int32-hex-buffered *(ebp+8) %eax)
13975         (write-buffered *(ebp+8) "/imm32\n")
13976       }
13977 $emit-cleanup-code-until-depth:continue:
13978       # curr -= 12
13979       81 5/subop/subtract %esi 0xc/imm32
13980       e9/jump loop/disp32
13981     }
13982 $emit-cleanup-code-until-depth:end:
13983     # . restore registers
13984     5e/pop-to-esi
13985     5b/pop-to-ebx
13986     5a/pop-to-edx
13987     59/pop-to-ecx
13988     58/pop-to-eax
13989     # . epilogue
13990     89/<- %esp 5/r32/ebp
13991     5d/pop-to-ebp
13992     c3/return
13993 
13994 # emit clean-up code for 'vars' until a given label is encountered
13995 # doesn't actually modify 'vars' so we need traverse manually inside the stack
13996 emit-cleanup-code-until-target:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-label: (addr array byte)
13997     # . prologue
13998     55/push-ebp
13999     89/<- %ebp 4/r32/esp
14000     # . save registers
14001     50/push-eax
14002     51/push-ecx
14003     52/push-edx
14004     53/push-ebx
14005     # ecx = vars
14006     8b/-> *(ebp+0xc) 1/r32/ecx
14007     # var eax: int = vars->top
14008     8b/-> *ecx 0/r32/eax
14009     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
14010     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
14011     # var min/ecx: (addr handle var) = vars->data
14012     81 0/subop/add %ecx 8/imm32
14013     {
14014 $emit-cleanup-code-until-target:loop:
14015       # if (curr < min) break
14016       39/compare %edx 1/r32/ecx
14017       0f 82/jump-if-addr< break/disp32
14018       # var v/ebx: (handle var) = lookup(*curr)
14019       (lookup *edx *(edx+4))  # => eax
14020       89/<- %ebx 0/r32/eax
14021       # if (v->name == until-block-label) break
14022       (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
14023       (string-equal? %eax *(ebp+0x10))  # => eax
14024       3d/compare-eax-and 0/imm32/false
14025       0f 85/jump-if-!= break/disp32
14026       # if v is in a register
14027       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
14028       {
14029         0f 84/jump-if-= break/disp32
14030         {
14031 $emit-cleanup-code-until-target:check-for-previous-spill:
14032           8b/-> *(edx+8) 0/r32/eax  # Live-var-register-spilled
14033           3d/compare-eax-and 0/imm32/false
14034           74/jump-if-= break/disp8
14035 $emit-cleanup-code-until-target:reclaim-var-in-register:
14036           (emit-indent *(ebp+8) *Curr-block-depth)
14037           (write-buffered *(ebp+8) "8f 0/subop/pop %")
14038           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
14039           (write-buffered *(ebp+8) %eax)
14040           (write-buffered *(ebp+8) Newline)
14041         }
14042         eb/jump $emit-cleanup-code-until-target:continue/disp8
14043       }
14044       # otherwise v is on the stack
14045       {
14046         75/jump-if-!= break/disp8
14047 $emit-cleanup-code-until-target:reclaim-var-on-stack:
14048         (size-of %ebx)  # => eax
14049         # don't emit code for labels
14050         3d/compare-eax-and 0/imm32
14051         74/jump-if-= break/disp8
14052         #
14053         (emit-indent *(ebp+8) *Curr-block-depth)
14054         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
14055         (write-int32-hex-buffered *(ebp+8) %eax)
14056         (write-buffered *(ebp+8) "/imm32\n")
14057       }
14058 $emit-cleanup-code-until-target:continue:
14059       # curr -= 12
14060       81 5/subop/subtract %edx 0xc/imm32
14061       e9/jump loop/disp32
14062     }
14063 $emit-cleanup-code-until-target:end:
14064     # . restore registers
14065     5b/pop-to-ebx
14066     5a/pop-to-edx
14067     59/pop-to-ecx
14068     58/pop-to-eax
14069     # . epilogue
14070     89/<- %esp 5/r32/ebp
14071     5d/pop-to-ebp
14072     c3/return
14073 
14074 # Return true if there isn't a variable in 'vars' with the same block-depth
14075 # and register as 'v'.
14076 # 'v' is guaranteed not to be within 'vars'.
14077 not-yet-spilled-this-block?:  # v: (addr var), vars: (addr stack live-var) -> result/eax: boolean
14078     # . prologue
14079     55/push-ebp
14080     89/<- %ebp 4/r32/esp
14081     # . save registers
14082     51/push-ecx
14083     52/push-edx
14084     53/push-ebx
14085     56/push-esi
14086     57/push-edi
14087     # ecx = vars
14088     8b/-> *(ebp+0xc) 1/r32/ecx
14089     # var eax: int = vars->top
14090     8b/-> *ecx 0/r32/eax
14091     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
14092     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
14093     # var min/ecx: (addr handle var) = vars->data
14094     8d/copy-address *(ecx+8) 1/r32/ecx
14095     # var depth/ebx: int = v->block-depth
14096     8b/-> *(ebp+8) 3/r32/ebx
14097     8b/-> *(ebx+0x10) 3/r32/ebx  # Var-block-depth
14098     # var needle/esi: (addr array byte) = v->register
14099     8b/-> *(ebp+8) 6/r32/esi
14100     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
14101     89/<- %esi 0/r32/eax
14102     {
14103 $not-yet-spilled-this-block?:loop:
14104       # if (curr < min) break
14105       39/compare %edx 1/r32/ecx
14106       0f 82/jump-if-addr< break/disp32
14107       # var cand/edi: (addr var) = lookup(*curr)
14108       (lookup *edx *(edx+4))  # => eax
14109       89/<- %edi 0/r32/eax
14110       # if (cand->block-depth < depth) break
14111       39/compare *(edi+0x10) 3/r32/ebx  # Var-block-depth
14112       0f 8c/jump-if-< break/disp32
14113       # var cand-reg/edi: (array array byte) = cand->reg
14114       (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
14115       89/<- %edi 0/r32/eax
14116       # if (cand-reg == null) continue
14117       {
14118 $not-yet-spilled-this-block?:check-reg:
14119         81 7/subop/compare %edi 0/imm32
14120         0f 84/jump-if-= break/disp32
14121         # if (cand-reg == needle) return true
14122         (string-equal? %esi %edi)  # => eax
14123         3d/compare-eax-and 0/imm32/false
14124         74/jump-if-= break/disp8
14125 $not-yet-spilled-this-block?:return-false:
14126         b8/copy-to-eax 0/imm32/false
14127         eb/jump $not-yet-spilled-this-block?:end/disp8
14128       }
14129 $not-yet-spilled-this-block?:continue:
14130       # curr -= 12
14131       81 5/subop/subtract %edx 0xc/imm32
14132       e9/jump loop/disp32
14133     }
14134 $not-yet-spilled-this-block?:return-true:
14135     # return true
14136     b8/copy-to-eax 1/imm32/true
14137 $not-yet-spilled-this-block?:end:
14138     # . restore registers
14139     5f/pop-to-edi
14140     5e/pop-to-esi
14141     5b/pop-to-ebx
14142     5a/pop-to-edx
14143     59/pop-to-ecx
14144     # . epilogue
14145     89/<- %esp 5/r32/ebp
14146     5d/pop-to-ebp
14147     c3/return
14148 
14149 # could the register of 'v' ever be written to by one of the vars in fn-outputs?
14150 will-not-write-some-register?:  # v: (addr var), stmts: (addr list stmt), fn: (addr function) -> result/eax: boolean
14151     # . prologue
14152     55/push-ebp
14153     89/<- %ebp 4/r32/esp
14154     # eax = v
14155     8b/-> *(ebp+8) 0/r32/eax
14156     # var reg/eax: (addr array byte) = lookup(v->register)
14157     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
14158     # var target/eax: (addr var) = find-register(fn-outputs, reg)
14159     (find-register *(ebp+0x10) %eax)  # => eax
14160     # if (target == 0) return true
14161     {
14162       3d/compare-eax-and 0/imm32
14163       75/jump-if-!= break/disp8
14164       b8/copy-to-eax 1/imm32/true
14165       eb/jump $will-not-write-some-register?:end/disp8
14166     }
14167     # return !assigns-in-stmts?(stmts, target)
14168     (assigns-in-stmts? *(ebp+0xc) %eax)  # => eax
14169     3d/compare-eax-and 0/imm32/false
14170     # assume: true = 1, so no need to mask with 0x000000ff
14171     0f 94/set-if-= %al
14172 $will-not-write-some-register?:end:
14173     # . epilogue
14174     89/<- %esp 5/r32/ebp
14175     5d/pop-to-ebp
14176     c3/return
14177 
14178 # return fn output with matching register
14179 # always returns false if 'reg' is null
14180 find-register:  # fn: (addr function), reg: (addr array byte) -> result/eax: (addr var)
14181     # . prologue
14182     55/push-ebp
14183     89/<- %ebp 4/r32/esp
14184     # . save registers
14185     51/push-ecx
14186     # var curr/ecx: (addr list var) = lookup(fn->outputs)
14187     8b/-> *(ebp+8) 1/r32/ecx
14188     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
14189     89/<- %ecx 0/r32/eax
14190     {
14191 $find-register:loop:
14192       # if (curr == 0) break
14193       81 7/subop/compare %ecx 0/imm32
14194       74/jump-if-= break/disp8
14195       # eax = curr->value->register
14196       (lookup *ecx *(ecx+4))  # List-value List-value => eax
14197       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
14198       # if (eax == reg) return curr->value
14199 $find-register:compare:
14200       (string-equal? *(ebp+0xc) %eax)  # => eax
14201       {
14202         3d/compare-eax-and 0/imm32/false
14203         74/jump-if-= break/disp8
14204 $find-register:found:
14205         (lookup *ecx *(ecx+4))  # List-value List-value => eax
14206         eb/jump $find-register:end/disp8
14207       }
14208       # curr = lookup(curr->next)
14209       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
14210       89/<- %ecx 0/r32/eax
14211       #
14212       eb/jump loop/disp8
14213     }
14214 $find-register:end:
14215     # . restore registers
14216     59/pop-to-ecx
14217     # . epilogue
14218     89/<- %esp 5/r32/ebp
14219     5d/pop-to-ebp
14220     c3/return
14221 
14222 assigns-in-stmts?:  # stmts: (addr list stmt), v: (addr var) -> result/eax: boolean
14223     # . prologue
14224     55/push-ebp
14225     89/<- %ebp 4/r32/esp
14226     # . save registers
14227     51/push-ecx
14228     # var curr/ecx: (addr list stmt) = stmts
14229     8b/-> *(ebp+8) 1/r32/ecx
14230     {
14231       # if (curr == 0) break
14232       81 7/subop/compare %ecx 0/imm32
14233       74/jump-if-= break/disp8
14234       # if assigns-in-stmt?(curr->value, v) return true
14235       (lookup *ecx *(ecx+4))  # List-value List-value => eax
14236       (assigns-in-stmt? %eax *(ebp+0xc))  # => eax
14237       3d/compare-eax-and 0/imm32/false
14238       75/jump-if-!= break/disp8
14239       # curr = lookup(curr->next)
14240       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
14241       89/<- %ecx 0/r32/eax
14242       #
14243       eb/jump loop/disp8
14244     }
14245 $assigns-in-stmts?:end:
14246     # . restore registers
14247     59/pop-to-ecx
14248     # . epilogue
14249     89/<- %esp 5/r32/ebp
14250     5d/pop-to-ebp
14251     c3/return
14252 
14253 assigns-in-stmt?:  # stmt: (addr stmt), v: (addr var) -> result/eax: boolean
14254     # . prologue
14255     55/push-ebp
14256     89/<- %ebp 4/r32/esp
14257     # . save registers
14258     51/push-ecx
14259     # ecx = stmt
14260     8b/-> *(ebp+8) 1/r32/ecx
14261     # if stmt is a stmt1, return assigns-in-stmt-vars?(stmt->outputs, v)
14262     {
14263       81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
14264       75/jump-if-!= break/disp8
14265       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
14266       (assigns-in-stmt-vars? %eax *(ebp+0xc))  # => eax
14267       eb/jump $assigns-in-stmt?:end/disp8
14268     }
14269     # if stmt is a block, return assigns-in-stmts?(stmt->stmts, v)
14270     {
14271       81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
14272       75/jump-if-!= break/disp8
14273       (lookup *(ecx+4) *(ecx+8))  # Block-stmts Block-stmts => eax
14274       (assigns-in-stmts? %eax *(ebp+0xc))  # => eax
14275       eb/jump $assigns-in-stmt?:end/disp8
14276     }
14277     # otherwise return false
14278     b8/copy 0/imm32/false
14279 $assigns-in-stmt?:end:
14280     # . restore registers
14281     59/pop-to-ecx
14282     # . epilogue
14283     89/<- %esp 5/r32/ebp
14284     5d/pop-to-ebp
14285     c3/return
14286 
14287 assigns-in-stmt-vars?:  # stmt-var: (addr stmt-var), v: (addr var) -> result/eax: boolean
14288     # . prologue
14289     55/push-ebp
14290     89/<- %ebp 4/r32/esp
14291     # . save registers
14292     51/push-ecx
14293     # var curr/ecx: (addr stmt-var) = stmt-var
14294     8b/-> *(ebp+8) 1/r32/ecx
14295     {
14296       # if (curr == 0) break
14297       81 7/subop/compare %ecx 0/imm32
14298       74/jump-if-= break/disp8
14299       # eax = lookup(curr->value)
14300       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
14301       # if (eax == v  &&  curr->is-deref? == false) return true
14302       {
14303         39/compare *(ebp+0xc) 0/r32/eax
14304         75/jump-if-!= break/disp8
14305         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
14306         75/jump-if-!= break/disp8
14307         b8/copy-to-eax 1/imm32/true
14308         eb/jump $assigns-in-stmt-vars?:end/disp8
14309       }
14310       # curr = lookup(curr->next)
14311       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
14312       89/<- %ecx 0/r32/eax
14313       #
14314       eb/jump loop/disp8
14315     }
14316 $assigns-in-stmt-vars?:end:
14317     # . restore registers
14318     59/pop-to-ecx
14319     # . epilogue
14320     89/<- %esp 5/r32/ebp
14321     5d/pop-to-ebp
14322     c3/return
14323 
14324 # is there a var before 'v' with the same block-depth and register on the 'vars' stack?
14325 # v is guaranteed to be within vars
14326 # 'start' is provided as an optimization, a pointer within vars
14327 # *start == v
14328 same-register-spilled-before?:  # v: (addr var), vars: (addr stack (handle var)), start: (addr var) -> result/eax: boolean
14329     # . prologue
14330     55/push-ebp
14331     89/<- %ebp 4/r32/esp
14332     # . save registers
14333     51/push-ecx
14334     52/push-edx
14335     53/push-ebx
14336     56/push-esi
14337     57/push-edi
14338     # ecx = v
14339     8b/-> *(ebp+8) 1/r32/ecx
14340     # var reg/edx: (addr array byte) = lookup(v->register)
14341     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
14342     89/<- %edx 0/r32/eax
14343     # var depth/ebx: int = v->block-depth
14344     8b/-> *(ecx+0x10) 3/r32/ebx  # Var-block-depth
14345     # var min/ecx: (addr handle var) = vars->data
14346     8b/-> *(ebp+0xc) 1/r32/ecx
14347     81 0/subop/add %ecx 8/imm32
14348     # TODO: check that start >= min and start < &vars->data[top]
14349     # TODO: check that *start == v
14350     # var curr/esi: (addr handle var) = start
14351     8b/-> *(ebp+0x10) 6/r32/esi
14352     # curr -= 8
14353     81 5/subop/subtract %esi 8/imm32
14354     {
14355 $same-register-spilled-before?:loop:
14356       # if (curr < min) break
14357       39/compare %esi 1/r32/ecx
14358       0f 82/jump-if-addr< break/disp32
14359       # var x/eax: (addr var) = lookup(*curr)
14360       (lookup *esi *(esi+4))  # => eax
14361       # if (x->block-depth < depth) break
14362       39/compare *(eax+0x10) 3/r32/ebx  # Var-block-depth
14363       0f 8c/jump-if-< break/disp32
14364       # if (x->register == 0) continue
14365       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
14366       74/jump-if-= $same-register-spilled-before?:continue/disp8
14367       # if (x->register == reg) return true
14368       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
14369       (string-equal? %eax %edx)  # => eax
14370       3d/compare-eax-and 0/imm32/false
14371       b8/copy-to-eax 1/imm32/true
14372       75/jump-if-!= $same-register-spilled-before?:end/disp8
14373 $same-register-spilled-before?:continue:
14374       # curr -= 8
14375       81 5/subop/subtract %esi 8/imm32
14376       e9/jump loop/disp32
14377     }
14378 $same-register-spilled-before?:false:
14379     b8/copy-to-eax 0/imm32/false
14380 $same-register-spilled-before?:end:
14381     # . restore registers
14382     5f/pop-to-edi
14383     5e/pop-to-esi
14384     5b/pop-to-ebx
14385     5a/pop-to-edx
14386     59/pop-to-ecx
14387     # . epilogue
14388     89/<- %esp 5/r32/ebp
14389     5d/pop-to-ebp
14390     c3/return
14391 
14392 # Clean up global state for 'vars' until some block depth (inclusive).
14393 #
14394 # This would be a simple series of pops, if it wasn't for fn outputs, which
14395 # can occur anywhere in the stack.
14396 # So we have to _compact_ the entire array underlying the stack.
14397 #
14398 # We want to allow a fn output register to be written to by locals before the
14399 # output is set.
14400 # So fn outputs can't just be pushed at the start of the function.
14401 #
14402 # We want to allow other locals to shadow a fn output register after the
14403 # output is set.
14404 # So the output can't just always override anything in the stack. Sequence matters.
14405 clean-up-blocks:  # vars: (addr stack live-var), until-block-depth: int, fn: (addr function)
14406     # pseudocode:
14407     #   to = vars->top  (which points outside the stack)
14408     #   while true
14409     #     if to <= 0
14410     #       break
14411     #     var v = vars->data[to-1]
14412     #     if v.depth < until and !in-function-outputs?(fn, v)
14413     #       break
14414     #     --to
14415     #   from = to
14416     #   while true
14417     #     if from >= vars->top
14418     #       break
14419     #     assert(from >= to)
14420     #     v = vars->data[from]
14421     #     if in-function-outputs?(fn, v)
14422     #       if from > to
14423     #         vars->data[to] = vars->data[from]
14424     #       ++to
14425     #     ++from
14426     #   vars->top = to
14427     #
14428     # . prologue
14429     55/push-ebp
14430     89/<- %ebp 4/r32/esp
14431     # . save registers
14432     50/push-eax
14433     52/push-edx
14434     53/push-ebx
14435     56/push-esi
14436     57/push-edi
14437     # ebx = vars
14438     8b/-> *(ebp+8) 3/r32/ebx
14439     # edx = until-block-depth
14440     8b/-> *(ebp+0xc) 2/r32/edx
14441 $clean-up-blocks:phase1:
14442     # var to/edi: int = vars->top
14443     8b/-> *ebx 7/r32/edi
14444     {
14445 $clean-up-blocks:loop1:
14446       # if (to <= 0) break
14447       81 7/subop/compare %edi 0/imm32
14448       7e/jump-if-<= break/disp8
14449       # var v/eax: (addr var) = lookup(vars->data[to-1]->var)
14450       8d/copy-address *(ebx+edi-4) 0/r32/eax  # vars + 8 + to - 12
14451       (lookup *eax *(eax+4))  # => eax
14452       # if (v->block-depth >= until-block-depth) continue
14453       39/compare *(eax+0x10) 2/r32/edx  # Var-block-depth
14454       {
14455         7d/jump-if->= break/disp8
14456         # if (!in-function-outputs?(fn, v)) break
14457         (in-function-outputs? *(ebp+0x10) %eax)  # => eax
14458         3d/compare-eax-and 0/imm32/false
14459         74/jump-if-= $clean-up-blocks:phase2/disp8
14460       }
14461 $clean-up-blocks:loop1-continue:
14462       # --to
14463       81 5/subop/subtract %edi 0xc/imm32
14464       #
14465       eb/jump loop/disp8
14466     }
14467 $clean-up-blocks:phase2:
14468     # var from/esi: int = to
14469     89/<- %esi 7/r32/edi
14470     {
14471 $clean-up-blocks:loop2:
14472       # if (from >= vars->top) break
14473       3b/compare 6/r32/esi *ebx
14474       7d/jump-if->= break/disp8
14475       # var v/eax: (addr var) = lookup(vars->data[from]->var)
14476       8d/copy-address *(ebx+esi+8) 0/r32/eax
14477       (lookup *eax *(eax+4))  # => eax
14478       # if !in-function-outputs?(fn, v) continue
14479       (in-function-outputs? *(ebp+0x10) %eax)  # => eax
14480       3d/compare-eax-and 0/imm32/false
14481       74/jump-if-= $clean-up-blocks:loop2-continue/disp8
14482       # invariant: from >= to
14483       # if (from > to) vars->data[to] = vars->data[from]
14484       {
14485         39/compare %esi 7/r32/edi
14486         7e/jump-if-<= break/disp8
14487         56/push-esi
14488         57/push-edi
14489         # . var from/esi: (addr byte) = &vars->data[from]
14490         8d/copy-address *(ebx+esi+8) 6/r32/esi
14491         # . var to/edi: (addr byte) = &vars->data[to]
14492         8d/copy-address *(ebx+edi+8) 7/r32/edi
14493         # .
14494         8b/-> *esi 0/r32/eax
14495         89/<- *edi 0/r32/eax
14496         8b/-> *(esi+4) 0/r32/eax
14497         89/<- *(edi+4) 0/r32/eax
14498         8b/-> *(esi+8) 0/r32/eax
14499         89/<- *(edi+8) 0/r32/eax
14500         5f/pop-to-edi
14501         5e/pop-to-esi
14502       }
14503       # ++to
14504       81 0/subop/add %edi 0xc/imm32
14505 $clean-up-blocks:loop2-continue:
14506       # ++from
14507       81 0/subop/add %esi 0xc/imm32
14508       #
14509       eb/jump loop/disp8
14510     }
14511     89/<- *ebx 7/r32/edi
14512 $clean-up-blocks:end:
14513     # . restore registers
14514     5f/pop-to-edi
14515     5e/pop-to-esi
14516     5b/pop-to-ebx
14517     5a/pop-to-edx
14518     58/pop-to-eax
14519     # . epilogue
14520     89/<- %esp 5/r32/ebp
14521     5d/pop-to-ebp
14522     c3/return
14523 
14524 in-function-outputs?:  # fn: (addr function), target: (addr var) -> result/eax: boolean
14525     # . prologue
14526     55/push-ebp
14527     89/<- %ebp 4/r32/esp
14528     # . save registers
14529     51/push-ecx
14530     # var curr/ecx: (addr list var) = lookup(fn->outputs)
14531     8b/-> *(ebp+8) 1/r32/ecx
14532     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
14533     89/<- %ecx 0/r32/eax
14534     # while curr != null
14535     {
14536       81 7/subop/compare %ecx 0/imm32
14537       74/jump-if-= break/disp8
14538       # var v/eax: (addr var) = lookup(curr->value)
14539       (lookup *ecx *(ecx+4))  # List-value List-value => eax
14540       # if (v == target) return true
14541       39/compare *(ebp+0xc) 0/r32/eax
14542       b8/copy-to-eax 1/imm32/true
14543       74/jump-if-= $in-function-outputs?:end/disp8
14544       # curr = curr->next
14545       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
14546       89/<- %ecx 0/r32/eax
14547       #
14548       eb/jump loop/disp8
14549     }
14550     b8/copy-to-eax 0/imm32
14551 $in-function-outputs?:end:
14552     # . restore registers
14553     59/pop-to-ecx
14554     # . epilogue
14555     89/<- %esp 5/r32/ebp
14556     5d/pop-to-ebp
14557     c3/return
14558 
14559 emit-subx-var-def:  # out: (addr buffered-file), stmt: (addr stmt)
14560     # . prologue
14561     55/push-ebp
14562     89/<- %ebp 4/r32/esp
14563     # . save registers
14564     50/push-eax
14565     51/push-ecx
14566     52/push-edx
14567     # eax = stmt
14568     8b/-> *(ebp+0xc) 0/r32/eax
14569     # var v/ecx: (addr var)
14570     (lookup *(eax+4) *(eax+8))  # Vardef-var Vardef-var => eax
14571     89/<- %ecx 0/r32/eax
14572     # v->block-depth = *Curr-block-depth
14573     8b/-> *Curr-block-depth 0/r32/eax
14574     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
14575     # var n/edx: int = size-of(stmt->var)
14576     (size-of %ecx)  # => eax
14577     89/<- %edx 0/r32/eax
14578     # *Curr-local-stack-offset -= n
14579     29/subtract-from *Curr-local-stack-offset 2/r32/edx
14580     # v->offset = *Curr-local-stack-offset
14581     8b/-> *Curr-local-stack-offset 0/r32/eax
14582     89/<- *(ecx+0x14) 0/r32/eax  # Var-offset
14583     # if v is an array, do something special to initialize it
14584     {
14585       (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
14586       (is-mu-array? %eax)  # => eax
14587       3d/compare-eax-and 0/imm32/false
14588       0f 84/jump-if-= break/disp32
14589       # var array-size-without-size/edx: int = n-4
14590       81 5/subop/subtract %edx 4/imm32
14591       #
14592       (emit-array-data-initialization *(ebp+8) %edx)
14593       e9/jump $emit-subx-var-def:end/disp32
14594     }
14595     # another special-case for initializing streams
14596     # a stream is an array with 2 extra pointers
14597     {
14598       (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
14599       (is-mu-stream? %eax)  # => eax
14600       3d/compare-eax-and 0/imm32/false
14601       0f 84/jump-if-= break/disp32
14602       # var array-size-without-size/edx: int = n-12
14603       81 5/subop/subtract %edx 0xc/imm32
14604       (emit-array-data-initialization *(ebp+8) %edx)
14605       # emit read and write pointers
14606       (emit-indent *(ebp+8) *Curr-block-depth)
14607       (write-buffered *(ebp+8) "68/push 0/imm32\n")
14608       (emit-indent *(ebp+8) *Curr-block-depth)
14609       (write-buffered *(ebp+8) "68/push 0/imm32\n")
14610       #
14611       eb/jump $emit-subx-var-def:end/disp8
14612     }
14613     # while n > 0
14614     {
14615       81 7/subop/compare %edx 0/imm32
14616       7e/jump-if-<= break/disp8
14617       (emit-indent *(ebp+8) *Curr-block-depth)
14618       (write-buffered *(ebp+8) "68/push 0/imm32\n")
14619       # n -= 4
14620       81 5/subop/subtract %edx 4/imm32
14621       #
14622       eb/jump loop/disp8
14623     }
14624 $emit-subx-var-def:end:
14625     # . restore registers
14626     5a/pop-to-edx
14627     59/pop-to-ecx
14628     58/pop-to-eax
14629     # . epilogue
14630     89/<- %esp 5/r32/ebp
14631     5d/pop-to-ebp
14632     c3/return
14633 
14634 emit-array-data-initialization:  # out: (addr buffered-file), n: int
14635     # . prologue
14636     55/push-ebp
14637     89/<- %ebp 4/r32/esp
14638     #
14639     (emit-indent *(ebp+8) *Curr-block-depth)
14640     (write-buffered *(ebp+8) "(push-n-zero-bytes ")
14641     (write-int32-hex-buffered *(ebp+8) *(ebp+0xc))
14642     (write-buffered *(ebp+8) ")\n")
14643     (emit-indent *(ebp+8) *Curr-block-depth)
14644     (write-buffered *(ebp+8) "68/push ")
14645     (write-int32-hex-buffered *(ebp+8) *(ebp+0xc))
14646     (write-buffered *(ebp+8) "/imm32\n")
14647 $emit-array-data-initialization:end:
14648     # . epilogue
14649     89/<- %esp 5/r32/ebp
14650     5d/pop-to-ebp
14651     c3/return
14652 
14653 emit-subx-stmt:  # out: (addr buffered-file), stmt: (addr stmt), primitives: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
14654     # . prologue
14655     55/push-ebp
14656     89/<- %ebp 4/r32/esp
14657     # . save registers
14658     50/push-eax
14659     51/push-ecx
14660     # - some special-case primitives that don't actually use the 'primitives' data structure
14661     # var op/ecx: (addr array byte) = lookup(stmt->operation)
14662     8b/-> *(ebp+0xc) 1/r32/ecx
14663     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
14664     89/<- %ecx 0/r32/eax
14665     # array size
14666     {
14667       # if (!string-equal?(stmt->operation, "length")) break
14668       (string-equal? %ecx "length")  # => eax
14669       3d/compare-eax-and 0/imm32
14670       0f 84/jump-if-= break/disp32
14671       (translate-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14672       e9/jump $emit-subx-stmt:end/disp32
14673     }
14674     # index into array
14675     {
14676       # if (!string-equal?(stmt->operation, "index")) break
14677       (string-equal? %ecx "index")  # => eax
14678       3d/compare-eax-and 0/imm32
14679       0f 84/jump-if-= break/disp32
14680       (translate-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14681       e9/jump $emit-subx-stmt:end/disp32
14682     }
14683     # compute-offset for index into array
14684     {
14685       # if (!string-equal?(stmt->operation, "compute-offset")) break
14686       (string-equal? %ecx "compute-offset")  # => eax
14687       3d/compare-eax-and 0/imm32
14688       0f 84/jump-if-= break/disp32
14689       (translate-mu-compute-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14690       e9/jump $emit-subx-stmt:end/disp32
14691     }
14692     # get field from record
14693     {
14694       # if (!string-equal?(stmt->operation, "get")) break
14695       (string-equal? %ecx "get")  # => eax
14696       3d/compare-eax-and 0/imm32
14697       0f 84/jump-if-= break/disp32
14698       (translate-mu-get-stmt *(ebp+8) *(ebp+0xc))
14699       e9/jump $emit-subx-stmt:end/disp32
14700     }
14701     # allocate scalar
14702     {
14703       # if (!string-equal?(stmt->operation, "allocate")) break
14704       (string-equal? %ecx "allocate")  # => eax
14705       3d/compare-eax-and 0/imm32
14706       0f 84/jump-if-= break/disp32
14707       (translate-mu-allocate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14708       e9/jump $emit-subx-stmt:end/disp32
14709     }
14710     # allocate array
14711     {
14712       # if (!string-equal?(stmt->operation, "populate")) break
14713       (string-equal? %ecx "populate")  # => eax
14714       3d/compare-eax-and 0/imm32
14715       0f 84/jump-if-= break/disp32
14716       (translate-mu-populate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14717       e9/jump $emit-subx-stmt:end/disp32
14718     }
14719     # allocate stream
14720     {
14721       # if (!string-equal?(stmt->operation, "populate-stream")) break
14722       (string-equal? %ecx "populate-stream")  # => eax
14723       3d/compare-eax-and 0/imm32
14724       0f 84/jump-if-= break/disp32
14725       (translate-mu-populate-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14726       e9/jump $emit-subx-stmt:end/disp32
14727     }
14728     # read from stream
14729     {
14730       # if (!string-equal?(stmt->operation, "read-from-stream")) break
14731       (string-equal? %ecx "read-from-stream")  # => eax
14732       3d/compare-eax-and 0/imm32
14733       0f 84/jump-if-= break/disp32
14734       (translate-mu-read-from-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14735       e9/jump $emit-subx-stmt:end/disp32
14736     }
14737     # write to stream
14738     {
14739       # if (!string-equal?(stmt->operation, "write-to-stream")) break
14740       (string-equal? %ecx "write-to-stream")  # => eax
14741       3d/compare-eax-and 0/imm32
14742       0f 84/jump-if-= break/disp32
14743       (translate-mu-write-to-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
14744       e9/jump $emit-subx-stmt:end/disp32
14745     }
14746     # - if stmt matches a primitive, emit it
14747     {
14748 $emit-subx-stmt:check-for-primitive:
14749       # var curr/eax: (addr primitive)
14750       (find-matching-primitive *(ebp+0x10) *(ebp+0xc))  # primitives, stmt => eax
14751       3d/compare-eax-and 0/imm32
14752       74/jump-if-= break/disp8
14753 $emit-subx-stmt:primitive:
14754       (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax)  # out, stmt, curr
14755       e9/jump $emit-subx-stmt:end/disp32
14756     }
14757     # - otherwise emit a call
14758     # TODO: type-checking
14759 $emit-subx-stmt:call:
14760     (emit-call *(ebp+8) *(ebp+0xc))
14761 $emit-subx-stmt:end:
14762     # . restore registers
14763     59/pop-to-ecx
14764     58/pop-to-eax
14765     # . epilogue
14766     89/<- %esp 5/r32/ebp
14767     5d/pop-to-ebp
14768     c3/return
14769 
14770 translate-mu-length-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
14771     # . prologue
14772     55/push-ebp
14773     89/<- %ebp 4/r32/esp
14774     # . save registers
14775     50/push-eax
14776     51/push-ecx
14777     52/push-edx
14778     53/push-ebx
14779     56/push-esi
14780     # esi = stmt
14781     8b/-> *(ebp+0xc) 6/r32/esi
14782     # var base/ebx: (addr var) = stmt->inouts[0]->value
14783     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
14784     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
14785     89/<- %ebx 0/r32/eax
14786     # var elemsize/ecx: int = array-element-size(base)
14787     (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
14788     89/<- %ecx 0/r32/eax
14789     # var outreg/edx: (addr array byte) = stmt->outputs[0]->value->register
14790     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
14791     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
14792     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
14793     89/<- %edx 0/r32/eax
14794     # if elemsize == 1
14795     {
14796       81 7/subop/compare %ecx 1/imm32
14797       75/jump-if-!= break/disp8
14798 $translate-mu-length-stmt:size-1:
14799       (emit-save-size-to *(ebp+8) %ebx %edx)
14800       e9/jump $translate-mu-length-stmt:end/disp32
14801     }
14802     # if elemsize is a power of 2 less than 256
14803     {
14804       (power-of-2? %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
14805       3d/compare-eax-and 0/imm32/false
14806       74/jump-if-= break/disp8
14807       81 7/subop/compare %ecx 0xff/imm32
14808       7f/jump-if-> break/disp8
14809 $translate-mu-length-stmt:size-power-of-2:
14810       (emit-save-size-to *(ebp+8) %ebx %edx)
14811       (emit-divide-by-shift-right *(ebp+8) %edx %ecx)
14812       e9/jump $translate-mu-length-stmt:end/disp32
14813     }
14814     # otherwise, the complex case
14815     # . emit register spills
14816     {
14817 $translate-mu-length-stmt:complex:
14818       (string-equal? %edx "eax")  # => eax
14819       3d/compare-eax-and 0/imm32/false
14820       75/break-if-!= break/disp8
14821       (emit-indent *(ebp+8) *Curr-block-depth)
14822       (write-buffered *(ebp+8) "50/push-eax\n")
14823     }
14824     {
14825       (string-equal? %edx "ecx")  # => eax
14826       3d/compare-eax-and 0/imm32/false
14827       75/break-if-!= break/disp8
14828       (emit-indent *(ebp+8) *Curr-block-depth)
14829       (write-buffered *(ebp+8) "51/push-ecx\n")
14830     }
14831     {
14832       (string-equal? %edx "edx")  # => eax
14833       3d/compare-eax-and 0/imm32/false
14834       75/break-if-!= break/disp8
14835       (emit-indent *(ebp+8) *Curr-block-depth)
14836       (write-buffered *(ebp+8) "52/push-edx\n")
14837     }
14838     # .
14839     (emit-save-size-to *(ebp+8) %ebx "eax")
14840     (emit-indent *(ebp+8) *Curr-block-depth)
14841     (write-buffered *(ebp+8) "31/xor %edx 2/r32/edx\n")
14842     (emit-indent *(ebp+8) *Curr-block-depth)
14843     (write-buffered *(ebp+8) "b9/copy-to-ecx ")
14844     (write-int32-hex-buffered *(ebp+8) %ecx)
14845     (write-buffered *(ebp+8) "/imm32\n")
14846     (emit-indent *(ebp+8) *Curr-block-depth)
14847     (write-buffered *(ebp+8) "f7 7/subop/idiv-eax-edx-by %ecx\n")
14848     {
14849       (string-equal? %edx "eax")  # => eax
14850       3d/compare-eax-and 0/imm32/false
14851       75/break-if-!= break/disp8
14852       (emit-indent *(ebp+8) *Curr-block-depth)
14853       (write-buffered *(ebp+8) "89/<- %")
14854       (write-buffered *(ebp+8) %edx)
14855       (write-buffered *(ebp+8) " 0/r32/eax\n")
14856     }
14857     # . emit register restores
14858     {
14859       (string-equal? %edx "edx")  # => eax
14860       3d/compare-eax-and 0/imm32/false
14861       75/break-if-!= break/disp8
14862       (emit-indent *(ebp+8) *Curr-block-depth)
14863       (write-buffered *(ebp+8) "5a/pop-to-edx\n")
14864     }
14865     {
14866       (string-equal? %edx "ecx")  # => eax
14867       3d/compare-eax-and 0/imm32/false
14868       75/break-if-!= break/disp8
14869       (emit-indent *(ebp+8) *Curr-block-depth)
14870       (write-buffered *(ebp+8) "59/pop-to-ecx\n")
14871     }
14872     {
14873       (string-equal? %edx "eax")  # => eax
14874       3d/compare-eax-and 0/imm32/false
14875       75/break-if-!= break/disp8
14876       (emit-indent *(ebp+8) *Curr-block-depth)
14877       (write-buffered *(ebp+8) "58/pop-to-eax\n")
14878     }
14879 $translate-mu-length-stmt:end:
14880     # . restore registers
14881     5e/pop-to-esi
14882     5b/pop-to-ebx
14883     5a/pop-to-edx
14884     59/pop-to-ecx
14885     58/pop-to-eax
14886     # . epilogue
14887     89/<- %esp 5/r32/ebp
14888     5d/pop-to-ebp
14889     c3/return
14890 
14891 array-element-size:  # arr: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
14892     # . prologue
14893     55/push-ebp
14894     89/<- %ebp 4/r32/esp
14895     #
14896     (array-element-type-id *(ebp+8) *(ebp+0xc) *(ebp+0x10))  # => eax
14897     (size-of-type-id-as-array-element %eax)  # => eax
14898 $array-element-size:end:
14899     # . epilogue
14900     89/<- %esp 5/r32/ebp
14901     5d/pop-to-ebp
14902     c3/return
14903 
14904 array-element-type-id:  # v: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: type-id
14905     # precondition: n is positive
14906     # . prologue
14907     55/push-ebp
14908     89/<- %ebp 4/r32/esp
14909     #
14910     8b/-> *(ebp+8) 0/r32/eax
14911     # var t/eax: (addr type-tree)
14912     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
14913     # if t == 0 abort
14914     3d/compare-eax-with 0/imm32
14915     0f 84/jump-if-== $array-element-type-id:error0/disp32
14916     # if t->is-atom? abort
14917     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14918     0f 85/jump-if-!= $array-element-type-id:error1/disp32
14919     # if (t->left == addr) t = t->right
14920     {
14921       50/push-eax
14922       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
14923       (is-simple-mu-type? %eax 2)  # addr => eax
14924       3d/compare-eax-with 0/imm32/false
14925       58/pop-to-eax
14926       74/jump-if-= break/disp8
14927 $array-element-type-id:skip-addr:
14928       (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
14929     }
14930     # if t == 0 abort
14931     3d/compare-eax-with 0/imm32
14932     0f 84/jump-if-= $array-element-type-id:error2/disp32
14933     # if t->is-atom? abort
14934     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14935     0f 85/jump-if-!= $array-element-type-id:error2/disp32
14936     # if t->left != array abort
14937     {
14938       50/push-eax
14939       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
14940       (is-simple-mu-type? %eax 3)  # array => eax
14941       3d/compare-eax-with 0/imm32/false
14942       58/pop-to-eax
14943 $array-element-type-id:no-array:
14944       0f 84/jump-if-= $array-element-type-id:error2/disp32
14945     }
14946 $array-element-type-id:skip-array:
14947     # t = t->right
14948     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
14949     # if t == 0 abort
14950     3d/compare-eax-with 0/imm32
14951     0f 84/jump-if-= $array-element-type-id:error2/disp32
14952     # if t->is-atom? abort
14953     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14954     0f 85/jump-if-!= $array-element-type-id:error2/disp32
14955     # return t->left->value
14956     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
14957     8b/-> *(eax+4) 0/r32/eax  # Type-tree-value
14958 $array-element-type-id:end:
14959     # . epilogue
14960     89/<- %esp 5/r32/ebp
14961     5d/pop-to-ebp
14962     c3/return
14963 
14964 $array-element-type-id:error0:
14965     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
14966     50/push-eax
14967     8b/-> *(ebp+8) 0/r32/eax
14968     (lookup *eax *(eax+4))  # Var-name Var-name => eax
14969     (write-buffered *(ebp+0xc) %eax)
14970     58/pop-to-eax
14971     (write-buffered *(ebp+0xc) "' has no type\n")
14972     (flush *(ebp+0xc))
14973     (stop *(ebp+0x10) 1)
14974     # never gets here
14975 
14976 $array-element-type-id:error1:
14977     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
14978     50/push-eax
14979     8b/-> *(ebp+8) 0/r32/eax
14980     (lookup *eax *(eax+4))  # Var-name Var-name => eax
14981     (write-buffered *(ebp+0xc) %eax)
14982     58/pop-to-eax
14983     (write-buffered *(ebp+0xc) "' has atomic type ")
14984     (write-int32-hex-buffered *(ebp+0xc) *(eax+4))  # Type-tree-value
14985     (write-buffered *(ebp+0xc) Newline)
14986     (flush *(ebp+0xc))
14987     (stop *(ebp+0x10) 1)
14988     # never gets here
14989 
14990 $array-element-type-id:error2:
14991     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
14992     50/push-eax
14993     8b/-> *(ebp+8) 0/r32/eax
14994     (lookup *eax *(eax+4))  # Var-name Var-name => eax
14995     (write-buffered *(ebp+0xc) %eax)
14996     58/pop-to-eax
14997     (write-buffered *(ebp+0xc) "' has non-array type\n")
14998     (flush *(ebp+0xc))
14999     (stop *(ebp+0x10) 1)
15000     # never gets here
15001 
15002 size-of-type-id-as-array-element:  # t: type-id -> result/eax: int
15003     # . prologue
15004     55/push-ebp
15005     89/<- %ebp 4/r32/esp
15006     # eax = t
15007     8b/-> *(ebp+8) 0/r32/eax
15008     # if t is 'byte', size is 1
15009     3d/compare-eax-and 8/imm32/byte
15010     {
15011       75/jump-if-!= break/disp8
15012       b8/copy-to-eax 1/imm32
15013       eb/jump $size-of-type-id-as-array-element:end/disp8
15014     }
15015     # otherwise proceed as usual
15016     (size-of-type-id %eax)  # => eax
15017 $size-of-type-id-as-array-element:end:
15018     # . epilogue
15019     89/<- %esp 5/r32/ebp
15020     5d/pop-to-ebp
15021     c3/return
15022 
15023 emit-save-size-to:  # out: (addr buffered-file), base: (addr var), outreg: (addr array byte)
15024     # . prologue
15025     55/push-ebp
15026     89/<- %ebp 4/r32/esp
15027     # . save registers
15028     50/push-eax
15029     53/push-ebx
15030     # ebx = base
15031     8b/-> *(ebp+0xc) 3/r32/ebx
15032     (emit-indent *(ebp+8) *Curr-block-depth)
15033     (write-buffered *(ebp+8) "8b/-> *")
15034     # if base is an (addr array ...) in a register
15035     {
15036       81 7/subop/compare *(ebx+0x18)) 0/imm32  # Var-register
15037       74/jump-if-= break/disp8
15038 $emit-save-size-to:emit-base-from-register:
15039       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
15040       (write-buffered *(ebp+8) %eax)
15041       eb/jump $emit-save-size-to:emit-output/disp8
15042     }
15043     # otherwise if base is an (array ...) on the stack
15044     {
15045       81 7/subop/compare *(ebx+0x14)) 0/imm32  # Var-offset
15046       74/jump-if-= break/disp8
15047 $emit-save-size-to:emit-base-from-stack:
15048       (write-buffered *(ebp+8) "(ebp+")
15049       (write-int32-hex-buffered *(ebp+8) *(ebx+0x14))  # Var-offset
15050       (write-buffered *(ebp+8) ")")
15051     }
15052 $emit-save-size-to:emit-output:
15053     (write-buffered *(ebp+8) " ")
15054     (get Mu-registers *(ebp+0x10) 0xc "Mu-registers")  # => eax
15055     (write-int32-hex-buffered *(ebp+8) *eax)
15056     (write-buffered *(ebp+8) "/r32\n")
15057 $emit-save-size-to:end:
15058     # . restore registers
15059     5b/pop-to-ebx
15060     58/pop-to-eax
15061     # . epilogue
15062     89/<- %esp 5/r32/ebp
15063     5d/pop-to-ebp
15064     c3/return
15065 
15066 emit-divide-by-shift-right:  # out: (addr buffered-file), reg: (addr array byte), size: int
15067     # . prologue
15068     55/push-ebp
15069     89/<- %ebp 4/r32/esp
15070     # . save registers
15071     50/push-eax
15072     #
15073     (emit-indent *(ebp+8) *Curr-block-depth)
15074     (write-buffered *(ebp+8) "c1/shift 5/subop/>> %")
15075     (write-buffered *(ebp+8) *(ebp+0xc))
15076     (write-buffered *(ebp+8) Space)
15077     (num-shift-rights *(ebp+0x10))  # => eax
15078     (write-int32-hex-buffered *(ebp+8) %eax)
15079     (write-buffered *(ebp+8) "/imm8\n")
15080 $emit-divide-by-shift-right:end:
15081     # . restore registers
15082     58/pop-to-eax
15083     # . epilogue
15084     89/<- %esp 5/r32/ebp
15085     5d/pop-to-ebp
15086     c3/return
15087 
15088 translate-mu-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15089     # . prologue
15090     55/push-ebp
15091     89/<- %ebp 4/r32/esp
15092     # . save registers
15093     51/push-ecx
15094     # ecx = stmt
15095     8b/-> *(ebp+0xc) 1/r32/ecx
15096     # var base/ecx: (addr var) = stmt->inouts[0]
15097     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15098     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15099     89/<- %ecx 0/r32/eax
15100     # if (var->register) do one thing
15101     {
15102       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
15103       74/jump-if-= break/disp8
15104       # TODO: ensure there's no dereference
15105       (translate-mu-index-stmt-with-array-in-register *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
15106       eb/jump $translate-mu-index-stmt:end/disp8
15107     }
15108     # if (var->offset) do a different thing
15109     {
15110       81 7/subop/compare *(ecx+0x14) 0/imm32  # Var-offset
15111       74/jump-if-= break/disp8
15112       # TODO: ensure there's no dereference
15113       (translate-mu-index-stmt-with-array-on-stack *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
15114       eb/jump $translate-mu-index-stmt:end/disp8
15115     }
15116 $translate-mu-index-stmt:end:
15117     # . restore registers
15118     59/pop-to-ecx
15119     # . epilogue
15120     89/<- %esp 5/r32/ebp
15121     5d/pop-to-ebp
15122     c3/return
15123 
15124 $translate-mu-index-stmt-with-array:error1:
15125     (write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input must either lie in a register or be a literal\n")
15126     (flush *(ebp+0x10))
15127     (stop *(ebp+0x14) 1)
15128     # never gets here
15129 
15130 $translate-mu-index-stmt-with-array:error2:
15131     (write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input when in a register must be an int or offset\n")
15132     (flush *(ebp+0x10))
15133     (stop *(ebp+0x14) 1)
15134     # never gets here
15135 
15136 translate-mu-index-stmt-with-array-in-register:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15137     # . prologue
15138     55/push-ebp
15139     89/<- %ebp 4/r32/esp
15140     # . save registers
15141     50/push-eax
15142     51/push-ecx
15143     52/push-edx
15144     53/push-ebx
15145     #
15146     (emit-indent *(ebp+8) *Curr-block-depth)
15147     (write-buffered *(ebp+8) "8d/copy-address *(")
15148     # TODO: ensure inouts[0] is in a register and not dereferenced
15149 $translate-mu-index-stmt-with-array-in-register:emit-base:
15150     # ecx = stmt
15151     8b/-> *(ebp+0xc) 1/r32/ecx
15152     # var base/ebx: (addr var) = inouts[0]
15153     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15154     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15155     89/<- %ebx 0/r32/eax
15156     # print base->register " + "
15157     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
15158     (write-buffered *(ebp+8) %eax)
15159     (write-buffered *(ebp+8) " + ")
15160     # var index/edx: (addr var) = inouts[1]
15161     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15162     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
15163     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15164     89/<- %edx 0/r32/eax
15165     # if index->register
15166     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
15167     {
15168       0f 84/jump-if-= break/disp32
15169 $translate-mu-index-stmt-with-array-in-register:emit-register-index:
15170       # if index is an int
15171       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
15172       (is-simple-mu-type? %eax 1)  # int => eax
15173       3d/compare-eax-and 0/imm32/false
15174       {
15175         0f 84/jump-if-= break/disp32
15176 $translate-mu-index-stmt-with-array-in-register:emit-int-register-index:
15177         # print index->register "<<" log2(array-element-size(base)) " + 4) "
15178         # . index->register "<<"
15179         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
15180         (write-buffered *(ebp+8) %eax)
15181         (write-buffered *(ebp+8) "<<")
15182         # . log2(array-element-size(base->type))
15183         # TODO: ensure size is a power of 2
15184         (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
15185         (num-shift-rights %eax)  # => eax
15186         (write-int32-hex-buffered *(ebp+8) %eax)
15187         e9/jump $translate-mu-index-stmt-with-array-in-register:emit-register-index-done/disp32
15188       }
15189       # if index->type is any other atom, abort
15190       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
15191       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
15192       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
15193       # if index has type (offset ...)
15194       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
15195       (is-simple-mu-type? %eax 7)  # => eax
15196       3d/compare-eax-and 0/imm32/false
15197       {
15198         0f 84/jump-if-= break/disp32
15199         # print index->register
15200 $translate-mu-index-stmt-with-array-in-register:emit-offset-register-index:
15201         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
15202         (write-buffered *(ebp+8) %eax)
15203       }
15204 $translate-mu-index-stmt-with-array-in-register:emit-register-index-done:
15205       (write-buffered *(ebp+8) " + 4) ")
15206       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
15207     }
15208     # otherwise if index is a literal
15209     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
15210     (is-simple-mu-type? %eax 0)  # => eax
15211     3d/compare-eax-and 0/imm32/false
15212     {
15213       0f 84/jump-if-= break/disp32
15214 $translate-mu-index-stmt-with-array-in-register:emit-literal-index:
15215       # var index-value/edx: int = parse-hex-int(index->name)
15216       (lookup *edx *(edx+4))  # Var-name Var-name => eax
15217       (parse-hex-int %eax)  # => eax
15218       89/<- %edx 0/r32/eax
15219       # offset = idx-value * array-element-size(base->type)
15220       (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
15221       f7 4/subop/multiply-into-eax %edx  # clobbers edx
15222       # offset += 4 for array size
15223       05/add-to-eax 4/imm32
15224       # TODO: check edx for overflow
15225       # print offset
15226       (write-int32-hex-buffered *(ebp+8) %eax)
15227       (write-buffered *(ebp+8) ") ")
15228       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
15229     }
15230     # otherwise abort
15231     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
15232 $translate-mu-index-stmt-with-array-in-register:emit-output:
15233     # outputs[0] "/r32"
15234     8b/-> *(ebp+0xc) 1/r32/ecx
15235     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
15236     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15237     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15238     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
15239     (write-int32-hex-buffered *(ebp+8) *eax)
15240     (write-buffered *(ebp+8) "/r32\n")
15241 $translate-mu-index-stmt-with-array-in-register:end:
15242     # . restore registers
15243     5b/pop-to-ebx
15244     5a/pop-to-edx
15245     59/pop-to-ecx
15246     58/pop-to-eax
15247     # . epilogue
15248     89/<- %esp 5/r32/ebp
15249     5d/pop-to-ebp
15250     c3/return
15251 
15252 translate-mu-index-stmt-with-array-on-stack:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15253     # . prologue
15254     55/push-ebp
15255     89/<- %ebp 4/r32/esp
15256     # . save registers
15257     50/push-eax
15258     51/push-ecx
15259     52/push-edx
15260     53/push-ebx
15261     #
15262     (emit-indent *(ebp+8) *Curr-block-depth)
15263     (write-buffered *(ebp+8) "8d/copy-address *(ebp + ")
15264     # var curr/edx: (addr stmt-var) = lookup(stmt->inouts)
15265     8b/-> *(ebp+0xc) 0/r32/eax
15266     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15267     89/<- %edx 0/r32/eax
15268     # var base/ecx: (addr var) = lookup(curr->value)
15269     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15270     89/<- %ecx 0/r32/eax
15271     # var curr2/eax: (addr stmt-var) = lookup(curr->next)
15272     (lookup *(edx+8) *(edx+0xc))  # Stmt-var-next Stmt-var-next => eax
15273     # var index/edx: (handle var) = curr2->value
15274     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15275     89/<- %edx 0/r32/eax
15276     # if index->register
15277     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
15278     {
15279       0f 84/jump-if-= break/disp32
15280 $translate-mu-index-stmt-with-array-on-stack:emit-register-index:
15281       # if index is an int
15282       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
15283       (is-simple-mu-type? %eax 1)  # int => eax
15284       3d/compare-eax-and 0/imm32/false
15285       {
15286         0f 84/jump-if-= break/disp32
15287 $translate-mu-index-stmt-with-array-on-stack:emit-int-register-index:
15288         # print index->register "<<" log2(array-element-size(base)) " + " base->offset+4
15289         # . inouts[1]->register "<<"
15290         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
15291         (write-buffered *(ebp+8) %eax)
15292         (write-buffered *(ebp+8) "<<")
15293         # . log2(array-element-size(base))
15294         # TODO: ensure size is a power of 2
15295         (array-element-size %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
15296         (num-shift-rights %eax)  # => eax
15297         (write-int32-hex-buffered *(ebp+8) %eax)
15298         #
15299         (write-buffered *(ebp+8) " + ")
15300         #
15301         8b/-> *(ecx+0x14) 0/r32/eax  # Var-offset
15302         05/add-to-eax 4/imm32  # for array length
15303         (write-int32-hex-buffered *(ebp+8) %eax)
15304         e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done/disp32
15305       }
15306       # if index->type is any other atom, abort
15307       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
15308       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
15309       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
15310       # if index has type (offset ...)
15311       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
15312       (is-simple-mu-type? %eax 7)  # => eax
15313       3d/compare-eax-and 0/imm32/false
15314       {
15315         0f 84/jump-if-= break/disp32
15316         # print index->register
15317 $translate-mu-index-stmt-with-array-on-stack:emit-offset-register-index:
15318         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
15319         (write-buffered *(ebp+8) %eax)
15320       }
15321 $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done:
15322       (write-buffered *(ebp+8) ") ")
15323       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
15324     }
15325     # otherwise if index is a literal
15326     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
15327     (is-simple-mu-type? %eax 0)  # => eax
15328     3d/compare-eax-and 0/imm32/false
15329     {
15330       0f 84/jump-if-= break/disp32
15331 $translate-mu-index-stmt-with-array-on-stack:emit-literal-index:
15332       # var idx-value/edx: int = parse-hex-int(index->name)
15333       (lookup *edx *(edx+4))  # Var-name Var-name => eax
15334       (parse-hex-int %eax)  # Var-name => eax
15335       89/<- %edx 0/r32/eax
15336       # offset = idx-value * array-element-size(base)
15337       (array-element-size %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
15338       f7 4/subop/multiply-into-eax %edx  # clobbers edx
15339       # offset += base->offset
15340       03/add *(ecx+0x14) 0/r32/eax  # Var-offset
15341       # offset += 4 for array size
15342       05/add-to-eax 4/imm32
15343       # TODO: check edx for overflow
15344       # print offset
15345       (write-int32-hex-buffered *(ebp+8) %eax)
15346       (write-buffered *(ebp+8) ") ")
15347       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
15348     }
15349     # otherwise abort
15350     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
15351 $translate-mu-index-stmt-with-array-on-stack:emit-output:
15352     # outputs[0] "/r32"
15353     8b/-> *(ebp+0xc) 0/r32/eax
15354     (lookup *(eax+0x14) *(eax+0x18))  # Stmt1-outputs Stmt1-outputs => eax
15355     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15356     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15357     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
15358     (write-int32-hex-buffered *(ebp+8) *eax)
15359     (write-buffered *(ebp+8) "/r32\n")
15360 $translate-mu-index-stmt-with-array-on-stack:end:
15361     # . restore registers
15362     5b/pop-to-ebx
15363     5a/pop-to-edx
15364     59/pop-to-ecx
15365     58/pop-to-eax
15366     # . epilogue
15367     89/<- %esp 5/r32/ebp
15368     5d/pop-to-ebp
15369     c3/return
15370 
15371 translate-mu-compute-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15372     # . prologue
15373     55/push-ebp
15374     89/<- %ebp 4/r32/esp
15375     # . save registers
15376     50/push-eax
15377     51/push-ecx
15378     52/push-edx
15379     53/push-ebx
15380     #
15381     (emit-indent *(ebp+8) *Curr-block-depth)
15382     (write-buffered *(ebp+8) "69/multiply")
15383     # ecx = stmt
15384     8b/-> *(ebp+0xc) 1/r32/ecx
15385     # var first-inout/ebx: (addr stmt-var) = stmt->inouts[0]
15386     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15387     89/<- %ebx 0/r32/eax
15388 $translate-mu-compute-index-stmt:emit-index:
15389     (lookup *(ebx+8) *(ebx+0xc))  # Stmt-var-next Stmt-var-next => eax
15390     (emit-subx-var-as-rm32 *(ebp+8) %eax)
15391     (write-buffered *(ebp+8) Space)
15392 $translate-mu-compute-index-stmt:emit-elem-size:
15393     # var base/ebx: (addr var)
15394     (lookup *ebx *(ebx+4))  # Stmt-var-value Stmt-var-value => eax
15395     89/<- %ebx 0/r32/eax
15396     # print array-element-size(base)
15397     (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
15398     (write-int32-hex-buffered *(ebp+8) %eax)
15399     (write-buffered *(ebp+8) "/imm32 ")
15400 $translate-mu-compute-index-stmt:emit-output:
15401     # outputs[0] "/r32"
15402     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
15403     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15404     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15405     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
15406     (write-int32-hex-buffered *(ebp+8) *eax)
15407     (write-buffered *(ebp+8) "/r32\n")
15408 $translate-mu-compute-index-stmt:end:
15409     # . restore registers
15410     5b/pop-to-ebx
15411     5a/pop-to-edx
15412     59/pop-to-ecx
15413     58/pop-to-eax
15414     # . epilogue
15415     89/<- %esp 5/r32/ebp
15416     5d/pop-to-ebp
15417     c3/return
15418 
15419 translate-mu-get-stmt:  # out: (addr buffered-file), stmt: (addr stmt)
15420     # . prologue
15421     55/push-ebp
15422     89/<- %ebp 4/r32/esp
15423     # . save registers
15424     50/push-eax
15425     51/push-ecx
15426     52/push-edx
15427     #
15428     (emit-indent *(ebp+8) *Curr-block-depth)
15429     (write-buffered *(ebp+8) "8d/copy-address ")
15430     # ecx = stmt
15431     8b/-> *(ebp+0xc) 1/r32/ecx
15432     # var offset/edx: int = get offset of stmt
15433     (mu-get-offset %ecx)  # => eax
15434     89/<- %edx 0/r32/eax
15435     # var base/eax: (addr var) = stmt->inouts->value
15436     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15437     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15438     # if base is in a register
15439     81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
15440     {
15441       0f 84/jump-if-= break/disp32
15442 $translate-mu-get-stmt:emit-register-input:
15443       # emit "*(" base->register " + " offset ") "
15444       (write-buffered *(ebp+8) "*(")
15445       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15446       (write-buffered *(ebp+8) %eax)
15447       (write-buffered *(ebp+8) " + ")
15448       (write-int32-hex-buffered *(ebp+8) %edx)
15449       (write-buffered *(ebp+8) ") ")
15450       e9/jump $translate-mu-get-stmt:emit-output/disp32
15451     }
15452     # otherwise base is on the stack
15453     {
15454 $translate-mu-get-stmt:emit-stack-input:
15455       # emit "*(ebp + " inouts[0]->stack-offset + offset ") "
15456       (write-buffered *(ebp+8) "*(ebp+")
15457       03/add *(eax+0x14) 2/r32/edx  # Var-offset
15458       (write-int32-hex-buffered *(ebp+8) %edx)
15459       (write-buffered *(ebp+8) ") ")
15460       eb/jump $translate-mu-get-stmt:emit-output/disp8
15461     }
15462 $translate-mu-get-stmt:emit-output:
15463     # var output/eax: (addr var) = stmt->outputs->value
15464     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
15465     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15466     # emit offset->register "/r32"
15467     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15468     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
15469     (write-int32-hex-buffered *(ebp+8) *eax)
15470     (write-buffered *(ebp+8) "/r32\n")
15471 $translate-mu-get-stmt:end:
15472     # . restore registers
15473     5a/pop-to-edx
15474     59/pop-to-ecx
15475     58/pop-to-eax
15476     # . epilogue
15477     89/<- %esp 5/r32/ebp
15478     5d/pop-to-ebp
15479     c3/return
15480 
15481 translate-mu-allocate-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15482     # . prologue
15483     55/push-ebp
15484     89/<- %ebp 4/r32/esp
15485     # . save registers
15486     50/push-eax
15487     56/push-esi
15488     57/push-edi
15489     # esi = stmt
15490     8b/-> *(ebp+0xc) 6/r32/esi
15491     # var target/edi: (addr stmt-var) = stmt->inouts[0]
15492     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15493     89/<- %edi 0/r32/eax
15494     #
15495     (emit-indent *(ebp+8) *Curr-block-depth)
15496     (write-buffered *(ebp+8) "(allocate Heap ")
15497     (addr-handle-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
15498     (write-int32-hex-buffered *(ebp+8) %eax)
15499     (emit-subx-call-operand *(ebp+8) %edi)
15500     (write-buffered *(ebp+8) ")\n")
15501 $translate-mu-allocate-stmt:end:
15502     # . restore registers
15503     5f/pop-to-edi
15504     5e/pop-to-esi
15505     58/pop-to-eax
15506     # . epilogue
15507     89/<- %esp 5/r32/ebp
15508     5d/pop-to-ebp
15509     c3/return
15510 
15511 addr-handle-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
15512     # . prologue
15513     55/push-ebp
15514     89/<- %ebp 4/r32/esp
15515     # var t/eax: (addr type-tree) = s->value->type
15516     8b/-> *(ebp+8) 0/r32/eax
15517     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15518     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
15519     # TODO: check eax != 0
15520     # TODO: check !t->is-atom?
15521     # TODO: check t->left == addr
15522     # t = t->right
15523 $addr-handle-payload-size:skip-addr:
15524     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15525     # TODO: check eax != 0
15526     # TODO: check !t->is-atom?
15527     # TODO: check t->left == handle
15528     # t = t->right
15529 $addr-handle-payload-size:skip-handle:
15530     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15531     # TODO: check eax != 0
15532     # if !t->is-atom? t = t->left
15533     81 7/subop/compare *eax 0/imm32/false
15534     {
15535       75/jump-if-!= break/disp8
15536       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
15537     }
15538     # TODO: check t->is-atom?
15539     # return size(t->value)
15540     (size-of-type-id *(eax+4))  # Type-tree-value => eax
15541 $addr-handle-payload-size:end:
15542     # . epilogue
15543     89/<- %esp 5/r32/ebp
15544     5d/pop-to-ebp
15545     c3/return
15546 
15547 addr-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
15548     # . prologue
15549     55/push-ebp
15550     89/<- %ebp 4/r32/esp
15551     # var t/eax: (addr type-tree) = s->value->type
15552     8b/-> *(ebp+8) 0/r32/eax
15553     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15554     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
15555     # TODO: check eax != 0
15556     # TODO: check !t->is-atom?
15557     # TODO: check t->left == addr
15558     # t = t->right
15559 $addr-payload-size:skip-addr:
15560     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15561     # TODO: check eax != 0
15562     # if !t->is-atom? t = t->left
15563     81 7/subop/compare *eax 0/imm32/false
15564     {
15565       75/jump-if-!= break/disp8
15566       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
15567     }
15568     # TODO: check t->is-atom?
15569     # return size(t->value)
15570     (size-of-type-id *(eax+4))  # Type-tree-value => eax
15571 $addr-payload-size:end:
15572     # . epilogue
15573     89/<- %esp 5/r32/ebp
15574     5d/pop-to-ebp
15575     c3/return
15576 
15577 translate-mu-populate-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15578     # . prologue
15579     55/push-ebp
15580     89/<- %ebp 4/r32/esp
15581     # . save registers
15582     50/push-eax
15583     51/push-ecx
15584     56/push-esi
15585     57/push-edi
15586     # esi = stmt
15587     8b/-> *(ebp+0xc) 6/r32/esi
15588     # var target/edi: (addr stmt-var) = stmt->inouts[0]
15589     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15590     89/<- %edi 0/r32/eax
15591     # var len/ecx: (addr stmt-var) = stmt->inouts[1]
15592     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
15593     89/<- %ecx 0/r32/eax
15594     #
15595     (emit-indent *(ebp+8) *Curr-block-depth)
15596     (write-buffered *(ebp+8) "(allocate-array2 Heap ")
15597     (addr-handle-array-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
15598     (write-int32-hex-buffered *(ebp+8) %eax)
15599     (emit-subx-call-operand *(ebp+8) %ecx)
15600     (emit-subx-call-operand *(ebp+8) %edi)
15601     (write-buffered *(ebp+8) ")\n")
15602 $translate-mu-populate-stmt:end:
15603     # . restore registers
15604     5f/pop-to-edi
15605     5e/pop-to-esi
15606     59/pop-to-ecx
15607     58/pop-to-eax
15608     # . epilogue
15609     89/<- %esp 5/r32/ebp
15610     5d/pop-to-ebp
15611     c3/return
15612 
15613 translate-mu-populate-stream-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15614     # . prologue
15615     55/push-ebp
15616     89/<- %ebp 4/r32/esp
15617     # . save registers
15618     50/push-eax
15619     51/push-ecx
15620     56/push-esi
15621     57/push-edi
15622     # esi = stmt
15623     8b/-> *(ebp+0xc) 6/r32/esi
15624     # var target/edi: (addr stmt-var) = stmt->inouts[0]
15625     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15626     89/<- %edi 0/r32/eax
15627     # var len/ecx: (addr stmt-var) = stmt->inouts[1]
15628     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
15629     89/<- %ecx 0/r32/eax
15630     #
15631     (emit-indent *(ebp+8) *Curr-block-depth)
15632     (write-buffered *(ebp+8) "(new-stream Heap ")
15633     (addr-handle-stream-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
15634     (write-int32-hex-buffered *(ebp+8) %eax)
15635     (emit-subx-call-operand *(ebp+8) %ecx)
15636     (emit-subx-call-operand *(ebp+8) %edi)
15637     (write-buffered *(ebp+8) ")\n")
15638 $translate-mu-populate-stream-stmt:end:
15639     # . restore registers
15640     5f/pop-to-edi
15641     5e/pop-to-esi
15642     59/pop-to-ecx
15643     58/pop-to-eax
15644     # . epilogue
15645     89/<- %esp 5/r32/ebp
15646     5d/pop-to-ebp
15647     c3/return
15648 
15649 translate-mu-read-from-stream-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15650     # . prologue
15651     55/push-ebp
15652     89/<- %ebp 4/r32/esp
15653     # . save registers
15654     50/push-eax
15655     51/push-ecx
15656     56/push-esi
15657     57/push-edi
15658     # esi = stmt
15659     8b/-> *(ebp+0xc) 6/r32/esi
15660     # var stream/ecx: (addr stmt-var) = stmt->inouts[0]
15661     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15662     89/<- %ecx 0/r32/eax
15663     # var target/edi: (addr stmt-var) = stmt->inouts[1]
15664     (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
15665     89/<- %edi 0/r32/eax
15666     #
15667     (emit-indent *(ebp+8) *Curr-block-depth)
15668     (write-buffered *(ebp+8) "(read-from-stream")
15669     (emit-subx-call-operand *(ebp+8) %ecx)
15670     (emit-subx-call-operand *(ebp+8) %edi)
15671     (write-buffered *(ebp+8) Space)
15672     (addr-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
15673     (write-int32-hex-buffered *(ebp+8) %eax)
15674     (write-buffered *(ebp+8) ")\n")
15675 $translate-mu-read-from-stream-stmt:end:
15676     # . restore registers
15677     5f/pop-to-edi
15678     5e/pop-to-esi
15679     59/pop-to-ecx
15680     58/pop-to-eax
15681     # . epilogue
15682     89/<- %esp 5/r32/ebp
15683     5d/pop-to-ebp
15684     c3/return
15685 
15686 translate-mu-write-to-stream-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15687     # . prologue
15688     55/push-ebp
15689     89/<- %ebp 4/r32/esp
15690     # . save registers
15691     50/push-eax
15692     51/push-ecx
15693     56/push-esi
15694     57/push-edi
15695     # esi = stmt
15696     8b/-> *(ebp+0xc) 6/r32/esi
15697     # var stream/ecx: (addr stmt-var) = stmt->inouts[0]
15698     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15699     89/<- %ecx 0/r32/eax
15700     # var target/edi: (addr stmt-var) = stmt->inouts[1]
15701     (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
15702     89/<- %edi 0/r32/eax
15703     #
15704     (emit-indent *(ebp+8) *Curr-block-depth)
15705     (write-buffered *(ebp+8) "(write-to-stream")
15706     (emit-subx-call-operand *(ebp+8) %ecx)
15707     (flush *(ebp+8))
15708     (emit-subx-call-operand *(ebp+8) %edi)
15709     (flush *(ebp+8))
15710     (write-buffered *(ebp+8) Space)
15711     (flush *(ebp+8))
15712     (addr-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
15713     (write-int32-hex-buffered *(ebp+8) %eax)
15714     (write-buffered *(ebp+8) ")\n")
15715 $translate-mu-write-to-stream-stmt:end:
15716     # . restore registers
15717     5f/pop-to-edi
15718     5e/pop-to-esi
15719     59/pop-to-ecx
15720     58/pop-to-eax
15721     # . epilogue
15722     89/<- %esp 5/r32/ebp
15723     5d/pop-to-ebp
15724     c3/return
15725 
15726 addr-handle-array-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
15727     # . prologue
15728     55/push-ebp
15729     89/<- %ebp 4/r32/esp
15730     # var t/eax: (addr type-tree) = s->value->type
15731     8b/-> *(ebp+8) 0/r32/eax
15732     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15733     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
15734     # TODO: check eax != 0
15735     # TODO: check !t->is-atom?
15736     # TODO: check t->left == addr
15737     # t = t->right
15738 $addr-handle-array-payload-size:skip-addr:
15739     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15740     # TODO: check eax != 0
15741     # TODO: check !t->is-atom?
15742     # TODO: check t->left == handle
15743     # t = t->right
15744 $addr-handle-array-payload-size:skip-handle:
15745     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15746     # TODO: check eax != 0
15747     # TODO: check !t->is-atom?
15748     # TODO: check t->left == array
15749     # t = t->right
15750 $addr-handle-array-payload-size:skip-array:
15751     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15752     # TODO: check eax != 0
15753     # if !t->is-atom? t = t->left
15754     81 7/subop/compare *eax 0/imm32/false
15755     {
15756       75/jump-if-!= break/disp8
15757       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
15758     }
15759 $addr-handle-array-payload-size:compute-size:
15760     # TODO: check t->is-atom?
15761     # return size(t->value)
15762     (size-of-type-id-as-array-element *(eax+4))  # Type-tree-value => eax
15763 $addr-handle-array-payload-size:end:
15764     # . epilogue
15765     89/<- %esp 5/r32/ebp
15766     5d/pop-to-ebp
15767     c3/return
15768 
15769 addr-handle-stream-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
15770     # . prologue
15771     55/push-ebp
15772     89/<- %ebp 4/r32/esp
15773     # var t/eax: (addr type-tree) = s->value->type
15774     8b/-> *(ebp+8) 0/r32/eax
15775     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15776     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
15777     # TODO: check eax != 0
15778     # TODO: check !t->is-atom?
15779     # TODO: check t->left == addr
15780     # t = t->right
15781 $addr-handle-stream-payload-size:skip-addr:
15782     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15783     # TODO: check eax != 0
15784     # TODO: check !t->is-atom?
15785     # TODO: check t->left == handle
15786     # t = t->right
15787 $addr-handle-stream-payload-size:skip-handle:
15788     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15789     # TODO: check eax != 0
15790     # TODO: check !t->is-atom?
15791     # TODO: check t->left == stream
15792     # t = t->right
15793 $addr-handle-stream-payload-size:skip-stream:
15794     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
15795     # TODO: check eax != 0
15796     # if !t->is-atom? t = t->left
15797     81 7/subop/compare *eax 0/imm32/false
15798     {
15799       75/jump-if-!= break/disp8
15800       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
15801     }
15802 $addr-handle-stream-payload-size:compute-size:
15803     # TODO: check t->is-atom?
15804     # return size(t->value)
15805     (size-of-type-id-as-array-element *(eax+4))  # Type-tree-value => eax
15806 $addr-handle-stream-payload-size:end:
15807     # . epilogue
15808     89/<- %esp 5/r32/ebp
15809     5d/pop-to-ebp
15810     c3/return
15811 
15812 power-of-2?:  # n: int, err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: boolean
15813     # precondition: n is positive
15814     # . prologue
15815     55/push-ebp
15816     89/<- %ebp 4/r32/esp
15817     # eax = n
15818     8b/-> *(ebp+8) 0/r32/eax
15819     # if (n < 0) abort
15820     3d/compare-eax-with 0/imm32
15821     0f 8c/jump-if-< $power-of-2?:abort/disp32
15822     # var tmp/eax: int = n-1
15823     48/decrement-eax
15824     # var tmp2/eax: int = n & tmp
15825     23/and-> *(ebp+8) 0/r32/eax
15826     # return (tmp2 == 0)
15827     3d/compare-eax-and 0/imm32
15828     0f 94/set-byte-if-= %al
15829     81 4/subop/and %eax 0xff/imm32
15830 $power-of-2?:end:
15831     # . epilogue
15832     89/<- %esp 5/r32/ebp
15833     5d/pop-to-ebp
15834     c3/return
15835 
15836 $power-of-2?:abort:
15837     (write-buffered *(ebp+0xc) "power-of-2?: negative number\n")
15838     (flush *(ebp+0xc))
15839     (stop *(ebp+0x10) 1)
15840     # never gets here
15841 
15842 num-shift-rights:  # n: int -> result/eax: int
15843     # precondition: n is a positive power of 2
15844     # . prologue
15845     55/push-ebp
15846     89/<- %ebp 4/r32/esp
15847     # . save registers
15848     51/push-ecx
15849     # var curr/ecx: int = n
15850     8b/-> *(ebp+8) 1/r32/ecx
15851     # result = 0
15852     b8/copy-to-eax 0/imm32
15853     {
15854       # if (curr <= 1) break
15855       81 7/subop/compare %ecx 1/imm32
15856       7e/jump-if-<= break/disp8
15857       40/increment-eax
15858       c1/shift 5/subop/arithmetic-right %ecx 1/imm8
15859       eb/jump loop/disp8
15860     }
15861 $num-shift-rights:end:
15862     # . restore registers
15863     59/pop-to-ecx
15864     # . epilogue
15865     89/<- %esp 5/r32/ebp
15866     5d/pop-to-ebp
15867     c3/return
15868 
15869 mu-get-offset:  # stmt: (addr stmt) -> result/eax: int
15870     # . prologue
15871     55/push-ebp
15872     89/<- %ebp 4/r32/esp
15873     # var second-inout/eax: (addr stmt-var) = stmt->inouts->next
15874     8b/-> *(ebp+8) 0/r32/eax
15875     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15876     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
15877     # var output-var/eax: (addr var) = second-inout->value
15878     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15879 #?     (write-buffered Stderr "mu-get-offset: ")
15880 #?     (write-int32-hex-buffered Stderr %eax)
15881 #?     (write-buffered Stderr " name: ")
15882 #?     50/push-eax
15883 #?     (lookup *eax *(eax+4))  # Var-name
15884 #?     (write-buffered Stderr %eax)
15885 #?     58/pop-to-eax
15886 #?     (write-buffered Stderr Newline)
15887 #?     (flush Stderr)
15888     # return output-var->stack-offset
15889     8b/-> *(eax+0x14) 0/r32/eax  # Var-offset
15890 #?     (write-buffered Stderr "=> ")
15891 #?     (write-int32-hex-buffered Stderr %eax)
15892 #?     (write-buffered Stderr Newline)
15893 #?     (flush Stderr)
15894 $emit-get-offset:end:
15895     # . epilogue
15896     89/<- %esp 5/r32/ebp
15897     5d/pop-to-ebp
15898     c3/return
15899 
15900 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)
15901     # . prologue
15902     55/push-ebp
15903     89/<- %ebp 4/r32/esp
15904     # . save registers
15905     50/push-eax
15906     51/push-ecx
15907     56/push-esi
15908     # esi = block
15909     8b/-> *(ebp+0xc) 6/r32/esi
15910     # block->var->block-depth = *Curr-block-depth
15911     (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
15912     8b/-> *Curr-block-depth 1/r32/ecx
15913     89/<- *(eax+0x10) 1/r32/ecx  # Var-block-depth
15914     # var stmts/eax: (addr list stmt) = lookup(block->statements)
15915     (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
15916     #
15917     {
15918 $emit-subx-block:check-empty:
15919       3d/compare-eax-and 0/imm32
15920       0f 84/jump-if-= break/disp32
15921       (emit-indent *(ebp+8) *Curr-block-depth)
15922       (write-buffered *(ebp+8) "{\n")
15923       # var v/ecx: (addr var) = lookup(block->var)
15924       (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
15925       89/<- %ecx 0/r32/eax
15926       #
15927       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
15928       (write-buffered *(ebp+8) %eax)
15929       (write-buffered *(ebp+8) ":loop:\n")
15930       ff 0/subop/increment *Curr-block-depth
15931       (push *(ebp+0x10) *(esi+0xc))  # Block-var
15932       (push *(ebp+0x10) *(esi+0x10))  # Block-var
15933       (push *(ebp+0x10) 0)  # false
15934       # emit block->statements
15935       (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
15936       (emit-subx-stmt-list *(ebp+8) %eax *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
15937       (pop *(ebp+0x10))  # => eax
15938       (pop *(ebp+0x10))  # => eax
15939       (pop *(ebp+0x10))  # => eax
15940       ff 1/subop/decrement *Curr-block-depth
15941       (emit-indent *(ebp+8) *Curr-block-depth)
15942       (write-buffered *(ebp+8) "}\n")
15943       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
15944       (write-buffered *(ebp+8) %eax)
15945       (write-buffered *(ebp+8) ":break:\n")
15946     }
15947 $emit-subx-block:end:
15948     # . restore registers
15949     5e/pop-to-esi
15950     59/pop-to-ecx
15951     58/pop-to-eax
15952     # . epilogue
15953     89/<- %esp 5/r32/ebp
15954     5d/pop-to-ebp
15955     c3/return
15956 
15957 # Primitives supported
15958 # See mu_instructions for a summary of this linked-list data structure.
15959 #
15960 # For each operation, put variants with hard-coded registers before flexible ones.
15961 #
15962 # Unfortunately, our restrictions on addresses require that various fields in
15963 # primitives be handles, which complicates these definitions.
15964 #   - we need to insert dummy fields all over the place for fake alloc-ids
15965 #   - we can't use our syntax sugar of quoted literals for string fields
15966 #
15967 # Fake alloc-ids are needed because our type definitions up top require
15968 # handles but it's clearer to statically allocate these long-lived objects.
15969 # Fake alloc-ids are perfectly safe, but they can't be reclaimed.
15970 #
15971 # Every 'object' below starts with a fake alloc-id. It may also contain other
15972 # fake alloc-ids for various handle fields.
15973 #
15974 # I think of objects starting with a fake alloc-id as having type 'payload'.
15975 # It's not really intended to be created dynamically; for that use `allocate`
15976 # as usual.
15977 #
15978 # Idea for a notation to simplify such definitions:
15979 #   _Primitive-increment-eax:  # (payload primitive)
15980 #     0x11/alloc-id:fake:payload
15981 #     0x11 @(0x11 "increment")  # name
15982 #     0 0                       # inouts
15983 #     0x11 @(0x11/payload
15984 #            0x11 @(0x11/payload  # List-value
15985 #                   0 0             # Var-name
15986 #                   0x11 @(0x11     # Var-type
15987 #                          1/is-atom
15988 #                          1/value 0/unused   # Type-tree-left
15989 #                          0 0                # Type-tree-right
15990 #                         )
15991 #                   1               # block-depth
15992 #                   0               # stack-offset
15993 #                   0x11 @(0x11 "eax")  # Var-register
15994 #                  )
15995 #            0 0)                 # List-next
15996 #     ...
15997 #     _Primitive-increment-ecx/imm32/next
15998 #   ...
15999 # Awfully complex and non-obvious. But also clearly signals there's something
16000 # to learn here, so may be worth trying.
16001 #
16002 # '@' is just an initial thought. Punctuation used so far in Mu: () * % # / "
16003 #
16004 # For now we'll continue to just use comments and manually ensure they stay up
16005 # to date.
16006 == data
16007 Primitives:  # (addr primitive)
16008 # - increment/decrement
16009 _Primitive-increment-eax:  # (addr primitive)
16010     # var/eax <- increment => 40/increment-eax
16011     0x11/imm32/alloc-id:fake
16012     _string-increment/imm32/name
16013     0/imm32/no-inouts
16014     0/imm32/no-inouts
16015     0x11/imm32/alloc-id:fake
16016     Single-int-var-in-eax/imm32/outputs
16017     0x11/imm32/alloc-id:fake
16018     _string_40_increment_eax/imm32/subx-name
16019     0/imm32/no-rm32
16020     0/imm32/no-r32
16021     0/imm32/no-imm32
16022     0/imm32/no-imm8
16023     0/imm32/no-disp32
16024     0/imm32/output-is-write-only
16025     0x11/imm32/alloc-id:fake
16026     _Primitive-increment-ecx/imm32/next
16027 _Primitive-increment-ecx:  # (payload primitive)
16028     0x11/imm32/alloc-id:fake:payload
16029     # var/ecx <- increment => 41/increment-ecx
16030     0x11/imm32/alloc-id:fake
16031     _string-increment/imm32/name
16032     0/imm32/no-inouts
16033     0/imm32/no-inouts
16034     0x11/imm32/alloc-id:fake
16035     Single-int-var-in-ecx/imm32/outputs
16036     0x11/imm32/alloc-id:fake
16037     _string_41_increment_ecx/imm32/subx-name
16038     0/imm32/no-rm32
16039     0/imm32/no-r32
16040     0/imm32/no-imm32
16041     0/imm32/no-imm8
16042     0/imm32/no-disp32
16043     0/imm32/output-is-write-only
16044     0x11/imm32/alloc-id:fake
16045     _Primitive-increment-edx/imm32/next
16046 _Primitive-increment-edx:  # (payload primitive)
16047     0x11/imm32/alloc-id:fake:payload
16048     # var/edx <- increment => 42/increment-edx
16049     0x11/imm32/alloc-id:fake
16050     _string-increment/imm32/name
16051     0/imm32/no-inouts
16052     0/imm32/no-inouts
16053     0x11/imm32/alloc-id:fake
16054     Single-int-var-in-edx/imm32/outputs
16055     0x11/imm32/alloc-id:fake
16056     _string_42_increment_edx/imm32/subx-name
16057     0/imm32/no-rm32
16058     0/imm32/no-r32
16059     0/imm32/no-imm32
16060     0/imm32/no-imm8
16061     0/imm32/no-disp32
16062     0/imm32/output-is-write-only
16063     0x11/imm32/alloc-id:fake
16064     _Primitive-increment-ebx/imm32/next
16065 _Primitive-increment-ebx:  # (payload primitive)
16066     0x11/imm32/alloc-id:fake:payload
16067     # var/ebx <- increment => 43/increment-ebx
16068     0x11/imm32/alloc-id:fake
16069     _string-increment/imm32/name
16070     0/imm32/no-inouts
16071     0/imm32/no-inouts
16072     0x11/imm32/alloc-id:fake
16073     Single-int-var-in-ebx/imm32/outputs
16074     0x11/imm32/alloc-id:fake
16075     _string_43_increment_ebx/imm32/subx-name
16076     0/imm32/no-rm32
16077     0/imm32/no-r32
16078     0/imm32/no-imm32
16079     0/imm32/no-imm8
16080     0/imm32/no-disp32
16081     0/imm32/output-is-write-only
16082     0x11/imm32/alloc-id:fake
16083     _Primitive-increment-esi/imm32/next
16084 _Primitive-increment-esi:  # (payload primitive)
16085     0x11/imm32/alloc-id:fake:payload
16086     # var/esi <- increment => 46/increment-esi
16087     0x11/imm32/alloc-id:fake
16088     _string-increment/imm32/name
16089     0/imm32/no-inouts
16090     0/imm32/no-inouts
16091     0x11/imm32/alloc-id:fake
16092     Single-int-var-in-esi/imm32/outputs
16093     0x11/imm32/alloc-id:fake
16094     _string_46_increment_esi/imm32/subx-name
16095     0/imm32/no-rm32
16096     0/imm32/no-r32
16097     0/imm32/no-imm32
16098     0/imm32/no-imm8
16099     0/imm32/no-disp32
16100     0/imm32/output-is-write-only
16101     0x11/imm32/alloc-id:fake
16102     _Primitive-increment-edi/imm32/next
16103 _Primitive-increment-edi:  # (payload primitive)
16104     0x11/imm32/alloc-id:fake:payload
16105     # var/edi <- increment => 47/increment-edi
16106     0x11/imm32/alloc-id:fake
16107     _string-increment/imm32/name
16108     0/imm32/no-inouts
16109     0/imm32/no-inouts
16110     0x11/imm32/alloc-id:fake
16111     Single-int-var-in-edi/imm32/outputs
16112     0x11/imm32/alloc-id:fake
16113     _string_47_increment_edi/imm32/subx-name
16114     0/imm32/no-rm32
16115     0/imm32/no-r32
16116     0/imm32/no-imm32
16117     0/imm32/no-imm8
16118     0/imm32/no-disp32
16119     0/imm32/output-is-write-only
16120     0x11/imm32/alloc-id:fake
16121     _Primitive-decrement-eax/imm32/next
16122 _Primitive-decrement-eax:  # (payload primitive)
16123     0x11/imm32/alloc-id:fake:payload
16124     # var/eax <- decrement => 48/decrement-eax
16125     0x11/imm32/alloc-id:fake
16126     _string-decrement/imm32/name
16127     0/imm32/no-inouts
16128     0/imm32/no-inouts
16129     0x11/imm32/alloc-id:fake
16130     Single-int-var-in-eax/imm32/outputs
16131     0x11/imm32/alloc-id:fake
16132     _string_48_decrement_eax/imm32/subx-name
16133     0/imm32/no-rm32
16134     0/imm32/no-r32
16135     0/imm32/no-imm32
16136     0/imm32/no-imm8
16137     0/imm32/no-disp32
16138     0/imm32/output-is-write-only
16139     0x11/imm32/alloc-id:fake
16140     _Primitive-decrement-ecx/imm32/next
16141 _Primitive-decrement-ecx:  # (payload primitive)
16142     0x11/imm32/alloc-id:fake:payload
16143     # var/ecx <- decrement => 49/decrement-ecx
16144     0x11/imm32/alloc-id:fake
16145     _string-decrement/imm32/name
16146     0/imm32/no-inouts
16147     0/imm32/no-inouts
16148     0x11/imm32/alloc-id:fake
16149     Single-int-var-in-ecx/imm32/outputs
16150     0x11/imm32/alloc-id:fake
16151     _string_49_decrement_ecx/imm32/subx-name
16152     0/imm32/no-rm32
16153     0/imm32/no-r32
16154     0/imm32/no-imm32
16155     0/imm32/no-imm8
16156     0/imm32/no-disp32
16157     0/imm32/output-is-write-only
16158     0x11/imm32/alloc-id:fake
16159     _Primitive-decrement-edx/imm32/next
16160 _Primitive-decrement-edx:  # (payload primitive)
16161     0x11/imm32/alloc-id:fake:payload
16162     # var/edx <- decrement => 4a/decrement-edx
16163     0x11/imm32/alloc-id:fake
16164     _string-decrement/imm32/name
16165     0/imm32/no-inouts
16166     0/imm32/no-inouts
16167     0x11/imm32/alloc-id:fake
16168     Single-int-var-in-edx/imm32/outputs
16169     0x11/imm32/alloc-id:fake
16170     _string_4a_decrement_edx/imm32/subx-name
16171     0/imm32/no-rm32
16172     0/imm32/no-r32
16173     0/imm32/no-imm32
16174     0/imm32/no-imm8
16175     0/imm32/no-disp32
16176     0/imm32/output-is-write-only
16177     0x11/imm32/alloc-id:fake
16178     _Primitive-decrement-ebx/imm32/next
16179 _Primitive-decrement-ebx:  # (payload primitive)
16180     0x11/imm32/alloc-id:fake:payload
16181     # var/ebx <- decrement => 4b/decrement-ebx
16182     0x11/imm32/alloc-id:fake
16183     _string-decrement/imm32/name
16184     0/imm32/no-inouts
16185     0/imm32/no-inouts
16186     0x11/imm32/alloc-id:fake
16187     Single-int-var-in-ebx/imm32/outputs
16188     0x11/imm32/alloc-id:fake
16189     _string_4b_decrement_ebx/imm32/subx-name
16190     0/imm32/no-rm32
16191     0/imm32/no-r32
16192     0/imm32/no-imm32
16193     0/imm32/no-imm8
16194     0/imm32/no-disp32
16195     0/imm32/output-is-write-only
16196     0x11/imm32/alloc-id:fake
16197     _Primitive-decrement-esi/imm32/next
16198 _Primitive-decrement-esi:  # (payload primitive)
16199     0x11/imm32/alloc-id:fake:payload
16200     # var/esi <- decrement => 4e/decrement-esi
16201     0x11/imm32/alloc-id:fake
16202     _string-decrement/imm32/name
16203     0/imm32/no-inouts
16204     0/imm32/no-inouts
16205     0x11/imm32/alloc-id:fake
16206     Single-int-var-in-esi/imm32/outputs
16207     0x11/imm32/alloc-id:fake
16208     _string_4e_decrement_esi/imm32/subx-name
16209     0/imm32/no-rm32
16210     0/imm32/no-r32
16211     0/imm32/no-imm32
16212     0/imm32/no-imm8
16213     0/imm32/no-disp32
16214     0/imm32/output-is-write-only
16215     0x11/imm32/alloc-id:fake
16216     _Primitive-decrement-edi/imm32/next
16217 _Primitive-decrement-edi:  # (payload primitive)
16218     0x11/imm32/alloc-id:fake:payload
16219     # var/edi <- decrement => 4f/decrement-edi
16220     0x11/imm32/alloc-id:fake
16221     _string-decrement/imm32/name
16222     0/imm32/no-inouts
16223     0/imm32/no-inouts
16224     0x11/imm32/alloc-id:fake
16225     Single-int-var-in-edi/imm32/outputs
16226     0x11/imm32/alloc-id:fake
16227     _string_4f_decrement_edi/imm32/subx-name
16228     0/imm32/no-rm32
16229     0/imm32/no-r32
16230     0/imm32/no-imm32
16231     0/imm32/no-imm8
16232     0/imm32/no-disp32
16233     0/imm32/output-is-write-only
16234     0x11/imm32/alloc-id:fake
16235     _Primitive-increment-mem/imm32/next
16236 _Primitive-increment-mem:  # (payload primitive)
16237     0x11/imm32/alloc-id:fake:payload
16238     # increment var => ff 0/subop/increment *(ebp+__)
16239     0x11/imm32/alloc-id:fake
16240     _string-increment/imm32/name
16241     0x11/imm32/alloc-id:fake
16242     Single-int-var-in-mem/imm32/inouts
16243     0/imm32/no-outputs
16244     0/imm32/no-outputs
16245     0x11/imm32/alloc-id:fake
16246     _string_ff_subop_increment/imm32/subx-name
16247     1/imm32/rm32-is-first-inout
16248     0/imm32/no-r32
16249     0/imm32/no-imm32
16250     0/imm32/no-imm8
16251     0/imm32/no-disp32
16252     0/imm32/output-is-write-only
16253     0x11/imm32/alloc-id:fake
16254     _Primitive-increment-reg/imm32/next
16255 _Primitive-increment-reg:  # (payload primitive)
16256     0x11/imm32/alloc-id:fake:payload
16257     # var/reg <- increment => ff 0/subop/increment %__
16258     0x11/imm32/alloc-id:fake
16259     _string-increment/imm32/name
16260     0/imm32/no-inouts
16261     0/imm32/no-inouts
16262     0x11/imm32/alloc-id:fake
16263     Single-int-var-in-some-register/imm32/outputs
16264     0x11/imm32/alloc-id:fake
16265     _string_ff_subop_increment/imm32/subx-name
16266     3/imm32/rm32-is-first-output
16267     0/imm32/no-r32
16268     0/imm32/no-imm32
16269     0/imm32/no-imm8
16270     0/imm32/no-disp32
16271     0/imm32/output-is-write-only
16272     0x11/imm32/alloc-id:fake
16273     _Primitive-decrement-mem/imm32/next
16274 _Primitive-decrement-mem:  # (payload primitive)
16275     0x11/imm32/alloc-id:fake:payload
16276     # decrement var => ff 1/subop/decrement *(ebp+__)
16277     0x11/imm32/alloc-id:fake
16278     _string-decrement/imm32/name
16279     0x11/imm32/alloc-id:fake
16280     Single-int-var-in-mem/imm32/inouts
16281     0/imm32/no-outputs
16282     0/imm32/no-outputs
16283     0x11/imm32/alloc-id:fake
16284     _string_ff_subop_decrement/imm32/subx-name
16285     1/imm32/rm32-is-first-inout
16286     0/imm32/no-r32
16287     0/imm32/no-imm32
16288     0/imm32/no-imm8
16289     0/imm32/no-disp32
16290     0/imm32/output-is-write-only
16291     0x11/imm32/alloc-id:fake
16292     _Primitive-decrement-reg/imm32/next
16293 _Primitive-decrement-reg:  # (payload primitive)
16294     0x11/imm32/alloc-id:fake:payload
16295     # var/reg <- decrement => ff 1/subop/decrement %__
16296     0x11/imm32/alloc-id:fake
16297     _string-decrement/imm32/name
16298     0/imm32/no-inouts
16299     0/imm32/no-inouts
16300     0x11/imm32/alloc-id:fake
16301     Single-int-var-in-some-register/imm32/outputs
16302     0x11/imm32/alloc-id:fake
16303     _string_ff_subop_decrement/imm32/subx-name
16304     3/imm32/rm32-is-first-output
16305     0/imm32/no-r32
16306     0/imm32/no-imm32
16307     0/imm32/no-imm8
16308     0/imm32/no-disp32
16309     0/imm32/output-is-write-only
16310     0x11/imm32/alloc-id:fake
16311     _Primitive-add-to-eax/imm32/next
16312 # - add
16313 _Primitive-add-to-eax:  # (payload primitive)
16314     0x11/imm32/alloc-id:fake:payload
16315     # var/eax <- add lit => 05/add-to-eax lit/imm32
16316     0x11/imm32/alloc-id:fake
16317     _string-add/imm32/name
16318     0x11/imm32/alloc-id:fake
16319     Single-lit-var/imm32/inouts
16320     0x11/imm32/alloc-id:fake
16321     Single-int-var-in-eax/imm32/outputs
16322     0x11/imm32/alloc-id:fake
16323     _string_05_add_to_eax/imm32/subx-name
16324     0/imm32/no-rm32
16325     0/imm32/no-r32
16326     1/imm32/imm32-is-first-inout
16327     0/imm32/no-imm8
16328     0/imm32/no-disp32
16329     0/imm32/output-is-write-only
16330     0x11/imm32/alloc-id:fake
16331     _Primitive-add-reg-to-reg/imm32/next
16332 _Primitive-add-reg-to-reg:  # (payload primitive)
16333     0x11/imm32/alloc-id:fake:payload
16334     # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32
16335     0x11/imm32/alloc-id:fake
16336     _string-add/imm32/name
16337     0x11/imm32/alloc-id:fake
16338     Single-int-var-in-some-register/imm32/inouts
16339     0x11/imm32/alloc-id:fake
16340     Single-int-var-in-some-register/imm32/outputs
16341     0x11/imm32/alloc-id:fake
16342     _string_01_add_to/imm32/subx-name
16343     3/imm32/rm32-is-first-output
16344     1/imm32/r32-is-first-inout
16345     0/imm32/no-imm32
16346     0/imm32/no-imm8
16347     0/imm32/no-disp32
16348     0/imm32/output-is-write-only
16349     0x11/imm32/alloc-id:fake
16350     _Primitive-add-reg-to-mem/imm32/next
16351 _Primitive-add-reg-to-mem:  # (payload primitive)
16352     0x11/imm32/alloc-id:fake:payload
16353     # add-to var1 var2/reg => 01/add-to var1 var2/r32
16354     0x11/imm32/alloc-id:fake
16355     _string-add-to/imm32/name
16356     0x11/imm32/alloc-id:fake
16357     Two-args-int-stack-int-reg/imm32/inouts
16358     0/imm32/no-outputs
16359     0/imm32/no-outputs
16360     0x11/imm32/alloc-id:fake
16361     _string_01_add_to/imm32/subx-name
16362     1/imm32/rm32-is-first-inout
16363     2/imm32/r32-is-second-inout
16364     0/imm32/no-imm32
16365     0/imm32/no-imm8
16366     0/imm32/no-disp32
16367     0/imm32/output-is-write-only
16368     0x11/imm32/alloc-id:fake
16369     _Primitive-add-mem-to-reg/imm32/next
16370 _Primitive-add-mem-to-reg:  # (payload primitive)
16371     0x11/imm32/alloc-id:fake:payload
16372     # var1/reg <- add var2 => 03/add var2/rm32 var1/r32
16373     0x11/imm32/alloc-id:fake
16374     _string-add/imm32/name
16375     0x11/imm32/alloc-id:fake
16376     Single-int-var-in-mem/imm32/inouts
16377     0x11/imm32/alloc-id:fake
16378     Single-int-var-in-some-register/imm32/outputs
16379     0x11/imm32/alloc-id:fake
16380     _string_03_add/imm32/subx-name
16381     1/imm32/rm32-is-first-inout
16382     3/imm32/r32-is-first-output
16383     0/imm32/no-imm32
16384     0/imm32/no-imm8
16385     0/imm32/no-disp32
16386     0/imm32/output-is-write-only
16387     0x11/imm32/alloc-id:fake
16388     _Primitive-add-lit-to-reg/imm32/next
16389 _Primitive-add-lit-to-reg:  # (payload primitive)
16390     0x11/imm32/alloc-id:fake:payload
16391     # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32
16392     0x11/imm32/alloc-id:fake
16393     _string-add/imm32/name
16394     0x11/imm32/alloc-id:fake
16395     Single-lit-var/imm32/inouts
16396     0x11/imm32/alloc-id:fake
16397     Single-int-var-in-some-register/imm32/outputs
16398     0x11/imm32/alloc-id:fake
16399     _string_81_subop_add/imm32/subx-name
16400     3/imm32/rm32-is-first-output
16401     0/imm32/no-r32
16402     1/imm32/imm32-is-first-inout
16403     0/imm32/no-imm8
16404     0/imm32/no-disp32
16405     0/imm32/output-is-write-only
16406     0x11/imm32/alloc-id:fake
16407     _Primitive-add-lit-to-mem/imm32/next
16408 _Primitive-add-lit-to-mem:  # (payload primitive)
16409     0x11/imm32/alloc-id:fake:payload
16410     # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32
16411     0x11/imm32/alloc-id:fake
16412     _string-add-to/imm32/name
16413     0x11/imm32/alloc-id:fake
16414     Int-var-and-literal/imm32/inouts
16415     0/imm32/no-outputs
16416     0/imm32/no-outputs
16417     0x11/imm32/alloc-id:fake
16418     _string_81_subop_add/imm32/subx-name
16419     1/imm32/rm32-is-first-inout
16420     0/imm32/no-r32
16421     2/imm32/imm32-is-second-inout
16422     0/imm32/no-imm8
16423     0/imm32/no-disp32
16424     0/imm32/output-is-write-only
16425     0x11/imm32/alloc-id:fake
16426     _Primitive-subtract-from-eax/imm32/next
16427 # - subtract
16428 _Primitive-subtract-from-eax:  # (payload primitive)
16429     0x11/imm32/alloc-id:fake:payload
16430     # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32
16431     0x11/imm32/alloc-id:fake
16432     _string-subtract/imm32/name
16433     0x11/imm32/alloc-id:fake
16434     Single-lit-var/imm32/inouts
16435     0x11/imm32/alloc-id:fake
16436     Single-int-var-in-eax/imm32/outputs
16437     0x11/imm32/alloc-id:fake
16438     _string_2d_subtract_from_eax/imm32/subx-name
16439     0/imm32/no-rm32
16440     0/imm32/no-r32
16441     1/imm32/imm32-is-first-inout
16442     0/imm32/no-imm8
16443     0/imm32/no-disp32
16444     0/imm32/output-is-write-only
16445     0x11/imm32/alloc-id:fake
16446     _Primitive-subtract-reg-from-reg/imm32/next
16447 _Primitive-subtract-reg-from-reg:  # (payload primitive)
16448     0x11/imm32/alloc-id:fake:payload
16449     # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32
16450     0x11/imm32/alloc-id:fake
16451     _string-subtract/imm32/name
16452     0x11/imm32/alloc-id:fake
16453     Single-int-var-in-some-register/imm32/inouts
16454     0x11/imm32/alloc-id:fake
16455     Single-int-var-in-some-register/imm32/outputs
16456     0x11/imm32/alloc-id:fake
16457     _string_29_subtract_from/imm32/subx-name
16458     3/imm32/rm32-is-first-output
16459     1/imm32/r32-is-first-inout
16460     0/imm32/no-imm32
16461     0/imm32/no-imm8
16462     0/imm32/no-disp32
16463     0/imm32/output-is-write-only
16464     0x11/imm32/alloc-id:fake
16465     _Primitive-subtract-reg-from-mem/imm32/next
16466 _Primitive-subtract-reg-from-mem:  # (payload primitive)
16467     0x11/imm32/alloc-id:fake:payload
16468     # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32
16469     0x11/imm32/alloc-id:fake
16470     _string-subtract-from/imm32/name
16471     0x11/imm32/alloc-id:fake
16472     Two-args-int-stack-int-reg/imm32/inouts
16473     0/imm32/no-outputs
16474     0/imm32/no-outputs
16475     0x11/imm32/alloc-id:fake
16476     _string_29_subtract_from/imm32/subx-name
16477     1/imm32/rm32-is-first-inout
16478     2/imm32/r32-is-second-inout
16479     0/imm32/no-imm32
16480     0/imm32/no-imm8
16481     0/imm32/no-disp32
16482     0/imm32/output-is-write-only
16483     0x11/imm32/alloc-id:fake
16484     _Primitive-subtract-mem-from-reg/imm32/next
16485 _Primitive-subtract-mem-from-reg:  # (payload primitive)
16486     0x11/imm32/alloc-id:fake:payload
16487     # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32
16488     0x11/imm32/alloc-id:fake
16489     _string-subtract/imm32/name
16490     0x11/imm32/alloc-id:fake
16491     Single-int-var-in-mem/imm32/inouts
16492     0x11/imm32/alloc-id:fake
16493     Single-int-var-in-some-register/imm32/outputs
16494     0x11/imm32/alloc-id:fake
16495     _string_2b_subtract/imm32/subx-name
16496     1/imm32/rm32-is-first-inout
16497     3/imm32/r32-is-first-output
16498     0/imm32/no-imm32
16499     0/imm32/no-imm8
16500     0/imm32/no-disp32
16501     0/imm32/output-is-write-only
16502     0x11/imm32/alloc-id:fake
16503     _Primitive-subtract-lit-from-reg/imm32/next
16504 _Primitive-subtract-lit-from-reg:  # (payload primitive)
16505     0x11/imm32/alloc-id:fake:payload
16506     # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32
16507     0x11/imm32/alloc-id:fake
16508     _string-subtract/imm32/name
16509     0x11/imm32/alloc-id:fake
16510     Single-lit-var/imm32/inouts
16511     0x11/imm32/alloc-id:fake
16512     Single-int-var-in-some-register/imm32/outputs
16513     0x11/imm32/alloc-id:fake
16514     _string_81_subop_subtract/imm32/subx-name
16515     3/imm32/rm32-is-first-output
16516     0/imm32/no-r32
16517     1/imm32/imm32-is-first-inout
16518     0/imm32/no-imm8
16519     0/imm32/no-disp32
16520     0/imm32/output-is-write-only
16521     0x11/imm32/alloc-id:fake
16522     _Primitive-subtract-lit-from-mem/imm32/next
16523 _Primitive-subtract-lit-from-mem:  # (payload primitive)
16524     0x11/imm32/alloc-id:fake:payload
16525     # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32
16526     0x11/imm32/alloc-id:fake
16527     _string-subtract-from/imm32/name
16528     0x11/imm32/alloc-id:fake
16529     Int-var-and-literal/imm32/inouts
16530     0/imm32/no-outputs
16531     0/imm32/no-outputs
16532     0x11/imm32/alloc-id:fake
16533     _string_81_subop_subtract/imm32/subx-name
16534     1/imm32/rm32-is-first-inout
16535     0/imm32/no-r32
16536     2/imm32/imm32-is-second-inout
16537     0/imm32/no-imm8
16538     0/imm32/no-disp32
16539     0/imm32/output-is-write-only
16540     0x11/imm32/alloc-id:fake
16541     _Primitive-and-with-eax/imm32/next
16542 # - and
16543 _Primitive-and-with-eax:  # (payload primitive)
16544     0x11/imm32/alloc-id:fake:payload
16545     # var/eax <- and lit => 25/and-with-eax lit/imm32
16546     0x11/imm32/alloc-id:fake
16547     _string-and/imm32/name
16548     0x11/imm32/alloc-id:fake
16549     Single-lit-var/imm32/inouts
16550     0x11/imm32/alloc-id:fake
16551     Single-int-var-in-eax/imm32/outputs
16552     0x11/imm32/alloc-id:fake
16553     _string_25_and_with_eax/imm32/subx-name
16554     0/imm32/no-rm32
16555     0/imm32/no-r32
16556     1/imm32/imm32-is-first-inout
16557     0/imm32/no-imm8
16558     0/imm32/no-disp32
16559     0/imm32/output-is-write-only
16560     0x11/imm32/alloc-id:fake
16561     _Primitive-and-reg-with-reg/imm32/next
16562 _Primitive-and-reg-with-reg:  # (payload primitive)
16563     0x11/imm32/alloc-id:fake:payload
16564     # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32
16565     0x11/imm32/alloc-id:fake
16566     _string-and/imm32/name
16567     0x11/imm32/alloc-id:fake
16568     Single-int-var-in-some-register/imm32/inouts
16569     0x11/imm32/alloc-id:fake
16570     Single-int-var-in-some-register/imm32/outputs
16571     0x11/imm32/alloc-id:fake
16572     _string_21_and_with/imm32/subx-name
16573     3/imm32/rm32-is-first-output
16574     1/imm32/r32-is-first-inout
16575     0/imm32/no-imm32
16576     0/imm32/no-imm8
16577     0/imm32/no-disp32
16578     0/imm32/output-is-write-only
16579     0x11/imm32/alloc-id:fake
16580     _Primitive-and-reg-with-mem/imm32/next
16581 _Primitive-and-reg-with-mem:  # (payload primitive)
16582     0x11/imm32/alloc-id:fake:payload
16583     # and-with var1 var2/reg => 21/and-with var1 var2/r32
16584     0x11/imm32/alloc-id:fake
16585     _string-and-with/imm32/name
16586     0x11/imm32/alloc-id:fake
16587     Two-args-int-stack-int-reg/imm32/inouts
16588     0/imm32/no-outputs
16589     0/imm32/no-outputs
16590     0x11/imm32/alloc-id:fake
16591     _string_21_and_with/imm32/subx-name
16592     1/imm32/rm32-is-first-inout
16593     2/imm32/r32-is-second-inout
16594     0/imm32/no-imm32
16595     0/imm32/no-imm8
16596     0/imm32/no-disp32
16597     0/imm32/output-is-write-only
16598     0x11/imm32/alloc-id:fake
16599     _Primitive-and-mem-with-reg/imm32/next
16600 _Primitive-and-mem-with-reg:  # (payload primitive)
16601     0x11/imm32/alloc-id:fake:payload
16602     # var1/reg <- and var2 => 23/and var2/rm32 var1/r32
16603     0x11/imm32/alloc-id:fake
16604     _string-and/imm32/name
16605     0x11/imm32/alloc-id:fake
16606     Single-int-var-in-mem/imm32/inouts
16607     0x11/imm32/alloc-id:fake
16608     Single-int-var-in-some-register/imm32/outputs
16609     0x11/imm32/alloc-id:fake
16610     _string_23_and/imm32/subx-name
16611     1/imm32/rm32-is-first-inout
16612     3/imm32/r32-is-first-output
16613     0/imm32/no-imm32
16614     0/imm32/no-imm8
16615     0/imm32/no-disp32
16616     0/imm32/output-is-write-only
16617     0x11/imm32/alloc-id:fake
16618     _Primitive-and-lit-with-reg/imm32/next
16619 _Primitive-and-lit-with-reg:  # (payload primitive)
16620     0x11/imm32/alloc-id:fake:payload
16621     # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32
16622     0x11/imm32/alloc-id:fake
16623     _string-and/imm32/name
16624     0x11/imm32/alloc-id:fake
16625     Single-lit-var/imm32/inouts
16626     0x11/imm32/alloc-id:fake
16627     Single-int-var-in-some-register/imm32/outputs
16628     0x11/imm32/alloc-id:fake
16629     _string_81_subop_and/imm32/subx-name
16630     3/imm32/rm32-is-first-output
16631     0/imm32/no-r32
16632     1/imm32/imm32-is-first-inout
16633     0/imm32/no-imm8
16634     0/imm32/no-disp32
16635     0/imm32/output-is-write-only
16636     0x11/imm32/alloc-id:fake
16637     _Primitive-and-lit-with-mem/imm32/next
16638 _Primitive-and-lit-with-mem:  # (payload primitive)
16639     0x11/imm32/alloc-id:fake:payload
16640     # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32
16641     0x11/imm32/alloc-id:fake
16642     _string-and-with/imm32/name
16643     0x11/imm32/alloc-id:fake
16644     Int-var-and-literal/imm32/inouts
16645     0/imm32/no-outputs
16646     0/imm32/no-outputs
16647     0x11/imm32/alloc-id:fake
16648     _string_81_subop_and/imm32/subx-name
16649     1/imm32/rm32-is-first-inout
16650     0/imm32/no-r32
16651     2/imm32/imm32-is-second-inout
16652     0/imm32/no-imm8
16653     0/imm32/no-disp32
16654     0/imm32/output-is-write-only
16655     0x11/imm32/alloc-id:fake
16656     _Primitive-or-with-eax/imm32/next
16657 # - or
16658 _Primitive-or-with-eax:  # (payload primitive)
16659     0x11/imm32/alloc-id:fake:payload
16660     # var/eax <- or lit => 0d/or-with-eax lit/imm32
16661     0x11/imm32/alloc-id:fake
16662     _string-or/imm32/name
16663     0x11/imm32/alloc-id:fake
16664     Single-lit-var/imm32/inouts
16665     0x11/imm32/alloc-id:fake
16666     Single-int-var-in-eax/imm32/outputs
16667     0x11/imm32/alloc-id:fake
16668     _string_0d_or_with_eax/imm32/subx-name
16669     0/imm32/no-rm32
16670     0/imm32/no-r32
16671     1/imm32/imm32-is-first-inout
16672     0/imm32/no-imm8
16673     0/imm32/no-disp32
16674     0/imm32/output-is-write-only
16675     0x11/imm32/alloc-id:fake
16676     _Primitive-or-reg-with-reg/imm32/next
16677 _Primitive-or-reg-with-reg:  # (payload primitive)
16678     0x11/imm32/alloc-id:fake:payload
16679     # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32
16680     0x11/imm32/alloc-id:fake
16681     _string-or/imm32/name
16682     0x11/imm32/alloc-id:fake
16683     Single-int-var-in-some-register/imm32/inouts
16684     0x11/imm32/alloc-id:fake
16685     Single-int-var-in-some-register/imm32/outputs
16686     0x11/imm32/alloc-id:fake
16687     _string_09_or_with/imm32/subx-name
16688     3/imm32/rm32-is-first-output
16689     1/imm32/r32-is-first-inout
16690     0/imm32/no-imm32
16691     0/imm32/no-imm8
16692     0/imm32/no-disp32
16693     0/imm32/output-is-write-only
16694     0x11/imm32/alloc-id:fake
16695     _Primitive-or-reg-with-mem/imm32/next
16696 _Primitive-or-reg-with-mem:  # (payload primitive)
16697     0x11/imm32/alloc-id:fake:payload
16698     # or-with var1 var2/reg => 09/or-with var1 var2/r32
16699     0x11/imm32/alloc-id:fake
16700     _string-or-with/imm32/name
16701     0x11/imm32/alloc-id:fake
16702     Two-args-int-stack-int-reg/imm32/inouts
16703     0/imm32/no-outputs
16704     0/imm32/no-outputs
16705     0x11/imm32/alloc-id:fake
16706     _string_09_or_with/imm32/subx-name
16707     1/imm32/rm32-is-first-inout
16708     2/imm32/r32-is-second-inout
16709     0/imm32/no-imm32
16710     0/imm32/no-imm8
16711     0/imm32/no-disp32
16712     0/imm32/output-is-write-only
16713     0x11/imm32/alloc-id:fake
16714     _Primitive-or-mem-with-reg/imm32/next
16715 _Primitive-or-mem-with-reg:  # (payload primitive)
16716     0x11/imm32/alloc-id:fake:payload
16717     # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32
16718     0x11/imm32/alloc-id:fake
16719     _string-or/imm32/name
16720     0x11/imm32/alloc-id:fake
16721     Single-int-var-in-mem/imm32/inouts
16722     0x11/imm32/alloc-id:fake
16723     Single-int-var-in-some-register/imm32/outputs
16724     0x11/imm32/alloc-id:fake
16725     _string_0b_or/imm32/subx-name
16726     1/imm32/rm32-is-first-inout
16727     3/imm32/r32-is-first-output
16728     0/imm32/no-imm32
16729     0/imm32/no-imm8
16730     0/imm32/no-disp32
16731     0/imm32/output-is-write-only
16732     0x11/imm32/alloc-id:fake
16733     _Primitive-or-lit-with-reg/imm32/next
16734 _Primitive-or-lit-with-reg:  # (payload primitive)
16735     0x11/imm32/alloc-id:fake:payload
16736     # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32
16737     0x11/imm32/alloc-id:fake
16738     _string-or/imm32/name
16739     0x11/imm32/alloc-id:fake
16740     Single-lit-var/imm32/inouts
16741     0x11/imm32/alloc-id:fake
16742     Single-int-var-in-some-register/imm32/outputs
16743     0x11/imm32/alloc-id:fake
16744     _string_81_subop_or/imm32/subx-name
16745     3/imm32/rm32-is-first-output
16746     0/imm32/no-r32
16747     1/imm32/imm32-is-first-inout
16748     0/imm32/no-imm8
16749     0/imm32/no-disp32
16750     0/imm32/output-is-write-only
16751     0x11/imm32/alloc-id:fake
16752     _Primitive-or-lit-with-mem/imm32/next
16753 _Primitive-or-lit-with-mem:  # (payload primitive)
16754     0x11/imm32/alloc-id:fake:payload
16755     # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32
16756     0x11/imm32/alloc-id:fake
16757     _string-or-with/imm32/name
16758     0x11/imm32/alloc-id:fake
16759     Int-var-and-literal/imm32/inouts
16760     0/imm32/no-outputs
16761     0/imm32/no-outputs
16762     0x11/imm32/alloc-id:fake
16763     _string_81_subop_or/imm32/subx-name
16764     1/imm32/rm32-is-first-inout
16765     0/imm32/no-r32
16766     2/imm32/imm32-is-second-inout
16767     0/imm32/no-imm8
16768     0/imm32/no-disp32
16769     0/imm32/output-is-write-only
16770     0x11/imm32/alloc-id:fake
16771     _Primitive-xor-with-eax/imm32/next
16772 # - xor
16773 _Primitive-xor-with-eax:  # (payload primitive)
16774     0x11/imm32/alloc-id:fake:payload
16775     # var/eax <- xor lit => 35/xor-with-eax lit/imm32
16776     0x11/imm32/alloc-id:fake
16777     _string-xor/imm32/name
16778     0x11/imm32/alloc-id:fake
16779     Single-lit-var/imm32/inouts
16780     0x11/imm32/alloc-id:fake
16781     Single-int-var-in-eax/imm32/outputs
16782     0x11/imm32/alloc-id:fake
16783     _string_35_xor_with_eax/imm32/subx-name
16784     0/imm32/no-rm32
16785     0/imm32/no-r32
16786     1/imm32/imm32-is-first-inout
16787     0/imm32/no-imm8
16788     0/imm32/no-disp32
16789     0/imm32/output-is-write-only
16790     0x11/imm32/alloc-id:fake
16791     _Primitive-xor-reg-with-reg/imm32/next
16792 _Primitive-xor-reg-with-reg:  # (payload primitive)
16793     0x11/imm32/alloc-id:fake:payload
16794     # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32
16795     0x11/imm32/alloc-id:fake
16796     _string-xor/imm32/name
16797     0x11/imm32/alloc-id:fake
16798     Single-int-var-in-some-register/imm32/inouts
16799     0x11/imm32/alloc-id:fake
16800     Single-int-var-in-some-register/imm32/outputs
16801     0x11/imm32/alloc-id:fake
16802     _string_31_xor_with/imm32/subx-name
16803     3/imm32/rm32-is-first-output
16804     1/imm32/r32-is-first-inout
16805     0/imm32/no-imm32
16806     0/imm32/no-imm8
16807     0/imm32/no-disp32
16808     0/imm32/output-is-write-only
16809     0x11/imm32/alloc-id:fake
16810     _Primitive-xor-reg-with-mem/imm32/next
16811 _Primitive-xor-reg-with-mem:  # (payload primitive)
16812     0x11/imm32/alloc-id:fake:payload
16813     # xor-with var1 var2/reg => 31/xor-with var1 var2/r32
16814     0x11/imm32/alloc-id:fake
16815     _string-xor-with/imm32/name
16816     0x11/imm32/alloc-id:fake
16817     Two-args-int-stack-int-reg/imm32/inouts
16818     0/imm32/no-outputs
16819     0/imm32/no-outputs
16820     0x11/imm32/alloc-id:fake
16821     _string_31_xor_with/imm32/subx-name
16822     1/imm32/rm32-is-first-inout
16823     2/imm32/r32-is-second-inout
16824     0/imm32/no-imm32
16825     0/imm32/no-imm8
16826     0/imm32/no-disp32
16827     0/imm32/output-is-write-only
16828     0x11/imm32/alloc-id:fake
16829     _Primitive-xor-mem-with-reg/imm32/next
16830 _Primitive-xor-mem-with-reg:  # (payload primitive)
16831     0x11/imm32/alloc-id:fake:payload
16832     # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32
16833     0x11/imm32/alloc-id:fake
16834     _string-xor/imm32/name
16835     0x11/imm32/alloc-id:fake
16836     Single-int-var-in-mem/imm32/inouts
16837     0x11/imm32/alloc-id:fake
16838     Single-int-var-in-some-register/imm32/outputs
16839     0x11/imm32/alloc-id:fake
16840     _string_33_xor/imm32/subx-name
16841     1/imm32/rm32-is-first-inout
16842     3/imm32/r32-is-first-output
16843     0/imm32/no-imm32
16844     0/imm32/no-imm8
16845     0/imm32/no-disp32
16846     0/imm32/output-is-write-only
16847     0x11/imm32/alloc-id:fake
16848     _Primitive-xor-lit-with-reg/imm32/next
16849 _Primitive-xor-lit-with-reg:  # (payload primitive)
16850     0x11/imm32/alloc-id:fake:payload
16851     # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32
16852     0x11/imm32/alloc-id:fake
16853     _string-xor/imm32/name
16854     0x11/imm32/alloc-id:fake
16855     Single-lit-var/imm32/inouts
16856     0x11/imm32/alloc-id:fake
16857     Single-int-var-in-some-register/imm32/outputs
16858     0x11/imm32/alloc-id:fake
16859     _string_81_subop_xor/imm32/subx-name
16860     3/imm32/rm32-is-first-output
16861     0/imm32/no-r32
16862     1/imm32/imm32-is-first-inout
16863     0/imm32/no-imm8
16864     0/imm32/no-disp32
16865     0/imm32/output-is-write-only
16866     0x11/imm32/alloc-id:fake
16867     _Primitive-xor-lit-with-mem/imm32/next
16868 _Primitive-xor-lit-with-mem:  # (payload primitive)
16869     0x11/imm32/alloc-id:fake:payload
16870     # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32
16871     0x11/imm32/alloc-id:fake
16872     _string-xor-with/imm32/name
16873     0x11/imm32/alloc-id:fake
16874     Int-var-and-literal/imm32/inouts
16875     0/imm32/no-outputs
16876     0/imm32/no-outputs
16877     0x11/imm32/alloc-id:fake
16878     _string_81_subop_xor/imm32/subx-name
16879     1/imm32/rm32-is-first-inout
16880     0/imm32/no-r32
16881     2/imm32/imm32-is-second-inout
16882     0/imm32/no-imm8
16883     0/imm32/no-disp32
16884     0/imm32/output-is-write-only
16885     0x11/imm32/alloc-id:fake
16886     _Primitive-shift-reg-left-by-lit/imm32/next
16887 _Primitive-shift-reg-left-by-lit:  # (payload primitive)
16888     0x11/imm32/alloc-id:fake:payload
16889     # var1/reg <- shift-left lit => c1/shift 4/subop/left var1/rm32 lit/imm32
16890     0x11/imm32/alloc-id:fake
16891     _string-shift-left/imm32/name
16892     0x11/imm32/alloc-id:fake
16893     Single-lit-var/imm32/inouts
16894     0x11/imm32/alloc-id:fake
16895     Single-int-var-in-some-register/imm32/outputs
16896     0x11/imm32/alloc-id:fake
16897     _string_c1_subop_shift_left/imm32/subx-name
16898     3/imm32/rm32-is-first-output
16899     0/imm32/no-r32
16900     0/imm32/no-imm32
16901     1/imm32/imm8-is-first-inout
16902     0/imm32/no-disp32
16903     0/imm32/output-is-write-only
16904     0x11/imm32/alloc-id:fake
16905     _Primitive-shift-reg-right-by-lit/imm32/next
16906 _Primitive-shift-reg-right-by-lit:  # (payload primitive)
16907     0x11/imm32/alloc-id:fake:payload
16908     # var1/reg <- shift-right lit => c1/shift 5/subop/right var1/rm32 lit/imm32
16909     0x11/imm32/alloc-id:fake
16910     _string-shift-right/imm32/name
16911     0x11/imm32/alloc-id:fake
16912     Single-lit-var/imm32/inouts
16913     0x11/imm32/alloc-id:fake
16914     Single-int-var-in-some-register/imm32/outputs
16915     0x11/imm32/alloc-id:fake
16916     _string_c1_subop_shift_right_padding_zeroes/imm32/subx-name
16917     3/imm32/rm32-is-first-output
16918     0/imm32/no-r32
16919     0/imm32/no-imm32
16920     1/imm32/imm8-is-first-inout
16921     0/imm32/no-disp32
16922     0/imm32/output-is-write-only
16923     0x11/imm32/alloc-id:fake
16924     _Primitive-shift-reg-right-signed-by-lit/imm32/next
16925 _Primitive-shift-reg-right-signed-by-lit:  # (payload primitive)
16926     0x11/imm32/alloc-id:fake:payload
16927     # var1/reg <- shift-right-signed lit => c1/shift 7/subop/right-preserving-sign var1/rm32 lit/imm32
16928     0x11/imm32/alloc-id:fake
16929     _string-shift-right-signed/imm32/name
16930     0x11/imm32/alloc-id:fake
16931     Single-lit-var/imm32/inouts
16932     0x11/imm32/alloc-id:fake
16933     Single-int-var-in-some-register/imm32/outputs
16934     0x11/imm32/alloc-id:fake
16935     _string_c1_subop_shift_right_preserving_sign/imm32/subx-name
16936     3/imm32/rm32-is-first-output
16937     0/imm32/no-r32
16938     0/imm32/no-imm32
16939     1/imm32/imm8-is-first-inout
16940     0/imm32/no-disp32
16941     0/imm32/output-is-write-only
16942     0x11/imm32/alloc-id:fake
16943     _Primitive-shift-mem-left-by-lit/imm32/next
16944 _Primitive-shift-mem-left-by-lit:  # (payload primitive)
16945     0x11/imm32/alloc-id:fake:payload
16946     # shift-left var1, lit => c1/shift 4/subop/left var1/rm32 lit/imm32
16947     0x11/imm32/alloc-id:fake
16948     _string-shift-left/imm32/name
16949     0x11/imm32/alloc-id:fake
16950     Int-var-and-literal/imm32/inouts
16951     0/imm32/no-outputs
16952     0/imm32/no-outputs
16953     0x11/imm32/alloc-id:fake
16954     _string_c1_subop_shift_left/imm32/subx-name
16955     1/imm32/rm32-is-first-inout
16956     0/imm32/no-r32
16957     0/imm32/no-imm32
16958     2/imm32/imm8-is-second-inout
16959     0/imm32/no-disp32
16960     0/imm32/output-is-write-only
16961     0x11/imm32/alloc-id:fake
16962     _Primitive-shift-mem-right-by-lit/imm32/next
16963 _Primitive-shift-mem-right-by-lit:  # (payload primitive)
16964     0x11/imm32/alloc-id:fake:payload
16965     # shift-right var1, lit => c1/shift 5/subop/right var1/rm32 lit/imm32
16966     0x11/imm32/alloc-id:fake
16967     _string-shift-right/imm32/name
16968     0x11/imm32/alloc-id:fake
16969     Int-var-and-literal/imm32/inouts
16970     0/imm32/no-outputs
16971     0/imm32/no-outputs
16972     0x11/imm32/alloc-id:fake
16973     _string_c1_subop_shift_right_padding_zeroes/imm32/subx-name
16974     1/imm32/rm32-is-first-inout
16975     0/imm32/no-r32
16976     0/imm32/no-imm32
16977     2/imm32/imm8-is-second-inout
16978     0/imm32/no-disp32
16979     0/imm32/output-is-write-only
16980     0x11/imm32/alloc-id:fake
16981     _Primitive-shift-mem-right-signed-by-lit/imm32/next
16982 _Primitive-shift-mem-right-signed-by-lit:  # (payload primitive)
16983     0x11/imm32/alloc-id:fake:payload
16984     # shift-right-signed var1, lit => c1/shift 7/subop/right-preserving-sign var1/rm32 lit/imm32
16985     0x11/imm32/alloc-id:fake
16986     _string-shift-right-signed/imm32/name
16987     0x11/imm32/alloc-id:fake
16988     Int-var-and-literal/imm32/inouts
16989     0/imm32/no-outputs
16990     0/imm32/no-outputs
16991     0x11/imm32/alloc-id:fake
16992     _string_c1_subop_shift_right_preserving_sign/imm32/subx-name
16993     1/imm32/rm32-is-first-inout
16994     0/imm32/no-r32
16995     0/imm32/no-imm32
16996     2/imm32/imm8-is-second-inout
16997     0/imm32/no-disp32
16998     0/imm32/output-is-write-only
16999     0x11/imm32/alloc-id:fake
17000     _Primitive-copy-to-eax/imm32/next
17001 # - copy
17002 _Primitive-copy-to-eax:  # (payload primitive)
17003     0x11/imm32/alloc-id:fake:payload
17004     # var/eax <- copy lit => b8/copy-to-eax lit/imm32
17005     0x11/imm32/alloc-id:fake
17006     _string-copy/imm32/name
17007     0x11/imm32/alloc-id:fake
17008     Single-lit-var/imm32/inouts
17009     0x11/imm32/alloc-id:fake
17010     Single-int-var-in-eax/imm32/outputs
17011     0x11/imm32/alloc-id:fake
17012     _string_b8_copy_to_eax/imm32/subx-name
17013     0/imm32/no-rm32
17014     0/imm32/no-r32
17015     1/imm32/imm32-is-first-inout
17016     0/imm32/no-imm8
17017     0/imm32/no-disp32
17018     1/imm32/output-is-write-only
17019     0x11/imm32/alloc-id:fake
17020     _Primitive-copy-to-ecx/imm32/next
17021 _Primitive-copy-to-ecx:  # (payload primitive)
17022     0x11/imm32/alloc-id:fake:payload
17023     # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32
17024     0x11/imm32/alloc-id:fake
17025     _string-copy/imm32/name
17026     0x11/imm32/alloc-id:fake
17027     Single-lit-var/imm32/inouts
17028     0x11/imm32/alloc-id:fake
17029     Single-int-var-in-ecx/imm32/outputs
17030     0x11/imm32/alloc-id:fake
17031     _string_b9_copy_to_ecx/imm32/subx-name
17032     0/imm32/no-rm32
17033     0/imm32/no-r32
17034     1/imm32/imm32-is-first-inout
17035     0/imm32/no-imm8
17036     0/imm32/no-disp32
17037     1/imm32/output-is-write-only
17038     0x11/imm32/alloc-id:fake
17039     _Primitive-copy-to-edx/imm32/next
17040 _Primitive-copy-to-edx:  # (payload primitive)
17041     0x11/imm32/alloc-id:fake:payload
17042     # var/edx <- copy lit => ba/copy-to-edx lit/imm32
17043     0x11/imm32/alloc-id:fake
17044     _string-copy/imm32/name
17045     0x11/imm32/alloc-id:fake
17046     Single-lit-var/imm32/inouts
17047     0x11/imm32/alloc-id:fake
17048     Single-int-var-in-edx/imm32/outputs
17049     0x11/imm32/alloc-id:fake
17050     _string_ba_copy_to_edx/imm32/subx-name
17051     0/imm32/no-rm32
17052     0/imm32/no-r32
17053     1/imm32/imm32-is-first-inout
17054     0/imm32/no-imm8
17055     0/imm32/no-disp32
17056     1/imm32/output-is-write-only
17057     0x11/imm32/alloc-id:fake
17058     _Primitive-copy-to-ebx/imm32/next
17059 _Primitive-copy-to-ebx:  # (payload primitive)
17060     0x11/imm32/alloc-id:fake:payload
17061     # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32
17062     0x11/imm32/alloc-id:fake
17063     _string-copy/imm32/name
17064     0x11/imm32/alloc-id:fake
17065     Single-lit-var/imm32/inouts
17066     0x11/imm32/alloc-id:fake
17067     Single-int-var-in-ebx/imm32/outputs
17068     0x11/imm32/alloc-id:fake
17069     _string_bb_copy_to_ebx/imm32/subx-name
17070     0/imm32/no-rm32
17071     0/imm32/no-r32
17072     1/imm32/imm32-is-first-inout
17073     0/imm32/no-imm8
17074     0/imm32/no-disp32
17075     1/imm32/output-is-write-only
17076     0x11/imm32/alloc-id:fake
17077     _Primitive-copy-to-esi/imm32/next
17078 _Primitive-copy-to-esi:  # (payload primitive)
17079     0x11/imm32/alloc-id:fake:payload
17080     # var/esi <- copy lit => be/copy-to-esi lit/imm32
17081     0x11/imm32/alloc-id:fake
17082     _string-copy/imm32/name
17083     0x11/imm32/alloc-id:fake
17084     Single-lit-var/imm32/inouts
17085     0x11/imm32/alloc-id:fake
17086     Single-int-var-in-esi/imm32/outputs
17087     0x11/imm32/alloc-id:fake
17088     _string_be_copy_to_esi/imm32/subx-name
17089     0/imm32/no-rm32
17090     0/imm32/no-r32
17091     1/imm32/imm32-is-first-inout
17092     0/imm32/no-imm8
17093     0/imm32/no-disp32
17094     1/imm32/output-is-write-only
17095     0x11/imm32/alloc-id:fake
17096     _Primitive-copy-to-edi/imm32/next
17097 _Primitive-copy-to-edi:  # (payload primitive)
17098     0x11/imm32/alloc-id:fake:payload
17099     # var/edi <- copy lit => bf/copy-to-edi lit/imm32
17100     0x11/imm32/alloc-id:fake
17101     _string-copy/imm32/name
17102     0x11/imm32/alloc-id:fake
17103     Single-lit-var/imm32/inouts
17104     0x11/imm32/alloc-id:fake
17105     Single-int-var-in-edi/imm32/outputs
17106     0x11/imm32/alloc-id:fake
17107     _string_bf_copy_to_edi/imm32/subx-name
17108     0/imm32/no-rm32
17109     0/imm32/no-r32
17110     1/imm32/imm32-is-first-inout
17111     0/imm32/no-imm8
17112     0/imm32/no-disp32
17113     1/imm32/output-is-write-only
17114     0x11/imm32/alloc-id:fake
17115     _Primitive-copy-reg-to-reg/imm32/next
17116 _Primitive-copy-reg-to-reg:  # (payload primitive)
17117     0x11/imm32/alloc-id:fake:payload
17118     # var1/reg <- copy var2/reg => 89/<- var1/rm32 var2/r32
17119     0x11/imm32/alloc-id:fake
17120     _string-copy/imm32/name
17121     0x11/imm32/alloc-id:fake
17122     Single-int-var-in-some-register/imm32/inouts
17123     0x11/imm32/alloc-id:fake
17124     Single-int-var-in-some-register/imm32/outputs
17125     0x11/imm32/alloc-id:fake
17126     _string_89_<-/imm32/subx-name
17127     3/imm32/rm32-is-first-output
17128     1/imm32/r32-is-first-inout
17129     0/imm32/no-imm32
17130     0/imm32/no-imm8
17131     0/imm32/no-disp32
17132     1/imm32/output-is-write-only
17133     0x11/imm32/alloc-id:fake
17134     _Primitive-copy-reg-to-mem/imm32/next
17135 _Primitive-copy-reg-to-mem:  # (payload primitive)
17136     0x11/imm32/alloc-id:fake:payload
17137     # copy-to var1 var2/reg => 89/<- var1 var2/r32
17138     0x11/imm32/alloc-id:fake
17139     _string-copy-to/imm32/name
17140     0x11/imm32/alloc-id:fake
17141     Two-args-int-stack-int-reg/imm32/inouts
17142     0/imm32/no-outputs
17143     0/imm32/no-outputs
17144     0x11/imm32/alloc-id:fake
17145     _string_89_<-/imm32/subx-name
17146     1/imm32/rm32-is-first-inout
17147     2/imm32/r32-is-second-inout
17148     0/imm32/no-imm32
17149     0/imm32/no-imm8
17150     0/imm32/no-disp32
17151     1/imm32/output-is-write-only
17152     0x11/imm32/alloc-id:fake
17153     _Primitive-copy-mem-to-reg/imm32/next
17154 _Primitive-copy-mem-to-reg:  # (payload primitive)
17155     0x11/imm32/alloc-id:fake:payload
17156     # var1/reg <- copy var2 => 8b/-> var2/rm32 var1/r32
17157     0x11/imm32/alloc-id:fake
17158     _string-copy/imm32/name
17159     0x11/imm32/alloc-id:fake
17160     Single-int-var-in-mem/imm32/inouts
17161     0x11/imm32/alloc-id:fake
17162     Single-int-var-in-some-register/imm32/outputs
17163     0x11/imm32/alloc-id:fake
17164     _string_8b_->/imm32/subx-name
17165     1/imm32/rm32-is-first-inout
17166     3/imm32/r32-is-first-output
17167     0/imm32/no-imm32
17168     0/imm32/no-imm8
17169     0/imm32/no-disp32
17170     1/imm32/output-is-write-only
17171     0x11/imm32/alloc-id:fake
17172     _Primitive-copy-lit-to-reg/imm32/next
17173 _Primitive-copy-lit-to-reg:  # (payload primitive)
17174     0x11/imm32/alloc-id:fake:payload
17175     # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32
17176     0x11/imm32/alloc-id:fake
17177     _string-copy/imm32/name
17178     0x11/imm32/alloc-id:fake
17179     Single-lit-var/imm32/inouts
17180     0x11/imm32/alloc-id:fake
17181     Single-int-var-in-some-register/imm32/outputs
17182     0x11/imm32/alloc-id:fake
17183     _string_c7_subop_copy/imm32/subx-name
17184     3/imm32/rm32-is-first-output
17185     0/imm32/no-r32
17186     1/imm32/imm32-is-first-inout
17187     0/imm32/no-imm8
17188     0/imm32/no-disp32
17189     1/imm32/output-is-write-only
17190     0x11/imm32/alloc-id:fake
17191     _Primitive-copy-lit-to-mem/imm32/next
17192 _Primitive-copy-lit-to-mem:  # (payload primitive)
17193     0x11/imm32/alloc-id:fake:payload
17194     # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32
17195     0x11/imm32/alloc-id:fake
17196     _string-copy-to/imm32/name
17197     0x11/imm32/alloc-id:fake
17198     Int-var-and-literal/imm32/inouts
17199     0/imm32/no-outputs
17200     0/imm32/no-outputs
17201     0x11/imm32/alloc-id:fake
17202     _string_c7_subop_copy/imm32/subx-name
17203     1/imm32/rm32-is-first-inout
17204     0/imm32/no-r32
17205     2/imm32/imm32-is-second-inout
17206     0/imm32/no-imm8
17207     0/imm32/no-disp32
17208     1/imm32/output-is-write-only
17209     0x11/imm32/alloc-id:fake
17210     _Primitive-copy-byte-from-reg/imm32/next
17211 # - copy byte
17212 _Primitive-copy-byte-from-reg:
17213     0x11/imm32/alloc-id:fake:payload
17214     # var/reg <- copy-byte var2/reg2 => 8a/byte-> %var2 var/r32
17215     0x11/imm32/alloc-id:fake
17216     _string-copy-byte/imm32/name
17217     0x11/imm32/alloc-id:fake
17218     Single-byte-var-in-some-register/imm32/inouts
17219     0x11/imm32/alloc-id:fake
17220     Single-byte-var-in-some-register/imm32/outputs
17221     0x11/imm32/alloc-id:fake
17222     _string_8a_copy_byte/imm32/subx-name
17223     1/imm32/rm32-is-first-inout
17224     3/imm32/r32-is-first-output
17225     0/imm32/no-imm32
17226     0/imm32/no-imm8
17227     0/imm32/no-disp32
17228     1/imm32/output-is-write-only
17229     0x11/imm32/alloc-id:fake
17230     _Primitive-copy-byte-from-mem/imm32/next
17231 _Primitive-copy-byte-from-mem:
17232     0x11/imm32/alloc-id:fake:payload
17233     # var/reg <- copy-byte *var2/reg2 => 8a/byte-> *var2 var/r32
17234     0x11/imm32/alloc-id:fake
17235     _string-copy-byte/imm32/name
17236     0x11/imm32/alloc-id:fake
17237     Single-byte-var-in-mem/imm32/inouts
17238     0x11/imm32/alloc-id:fake
17239     Single-byte-var-in-some-register/imm32/outputs
17240     0x11/imm32/alloc-id:fake
17241     _string_8a_copy_byte/imm32/subx-name
17242     1/imm32/rm32-is-first-inout
17243     3/imm32/r32-is-first-output
17244     0/imm32/no-imm32
17245     0/imm32/no-imm8
17246     0/imm32/no-disp32
17247     1/imm32/output-is-write-only
17248     0x11/imm32/alloc-id:fake
17249     _Primitive-copy-byte-to-mem/imm32/next
17250 _Primitive-copy-byte-to-mem:
17251     0x11/imm32/alloc-id:fake:payload
17252     # copy-byte-to *var1/reg1, var2/reg2 => 88/byte<- *reg1 reg2/r32
17253     0x11/imm32/alloc-id:fake
17254     _string-copy-byte-to/imm32/name
17255     0x11/imm32/alloc-id:fake
17256     Two-args-byte-stack-byte-reg/imm32/inouts
17257     0/imm32/no-outputs
17258     0/imm32/no-outputs
17259     0x11/imm32/alloc-id:fake
17260     _string_88_copy_byte/imm32/subx-name
17261     1/imm32/rm32-is-first-inout
17262     2/imm32/r32-is-second-inout
17263     0/imm32/no-imm32
17264     0/imm32/no-imm8
17265     0/imm32/no-disp32
17266     0/imm32/output-is-write-only
17267     0x11/imm32/alloc-id:fake
17268     _Primitive-address/imm32/next
17269 # - address
17270 _Primitive-address:  # (payload primitive)
17271     0x11/imm32/alloc-id:fake:payload
17272     # var1/reg <- address var2 => 8d/copy-address var2/rm32 var1/r32
17273     0x11/imm32/alloc-id:fake
17274     _string-address/imm32/name
17275     0x11/imm32/alloc-id:fake
17276     Single-int-var-in-mem/imm32/inouts
17277     0x11/imm32/alloc-id:fake
17278     Single-addr-var-in-some-register/imm32/outputs
17279     0x11/imm32/alloc-id:fake
17280     _string_8d_copy_address/imm32/subx-name
17281     1/imm32/rm32-is-first-inout
17282     3/imm32/r32-is-first-output
17283     0/imm32/no-imm32
17284     0/imm32/no-imm8
17285     0/imm32/no-disp32
17286     1/imm32/output-is-write-only
17287     0x11/imm32/alloc-id:fake
17288     _Primitive-compare-reg-with-reg/imm32/next
17289 # - compare
17290 _Primitive-compare-reg-with-reg:  # (payload primitive)
17291     0x11/imm32/alloc-id:fake:payload
17292     # compare var1/reg1 var2/reg2 => 39/compare var1/rm32 var2/r32
17293     0x11/imm32/alloc-id:fake
17294     _string-compare/imm32/name
17295     0x11/imm32/alloc-id:fake
17296     Two-int-args-in-regs/imm32/inouts
17297     0/imm32/no-outputs
17298     0/imm32/no-outputs
17299     0x11/imm32/alloc-id:fake
17300     _string_39_compare->/imm32/subx-name
17301     1/imm32/rm32-is-first-inout
17302     2/imm32/r32-is-second-inout
17303     0/imm32/no-imm32
17304     0/imm32/no-imm8
17305     0/imm32/no-disp32
17306     0/imm32/output-is-write-only
17307     0x11/imm32/alloc-id:fake
17308     _Primitive-compare-mem-with-reg/imm32/next
17309 _Primitive-compare-mem-with-reg:  # (payload primitive)
17310     0x11/imm32/alloc-id:fake:payload
17311     # compare var1 var2/reg => 39/compare var1/rm32 var2/r32
17312     0x11/imm32/alloc-id:fake
17313     _string-compare/imm32/name
17314     0x11/imm32/alloc-id:fake
17315     Two-args-int-stack-int-reg/imm32/inouts
17316     0/imm32/no-outputs
17317     0/imm32/no-outputs
17318     0x11/imm32/alloc-id:fake
17319     _string_39_compare->/imm32/subx-name
17320     1/imm32/rm32-is-first-inout
17321     2/imm32/r32-is-second-inout
17322     0/imm32/no-imm32
17323     0/imm32/no-imm8
17324     0/imm32/no-disp32
17325     0/imm32/output-is-write-only
17326     0x11/imm32/alloc-id:fake
17327     _Primitive-compare-reg-with-mem/imm32/next
17328 _Primitive-compare-reg-with-mem:  # (payload primitive)
17329     0x11/imm32/alloc-id:fake:payload
17330     # compare var1/reg var2 => 3b/compare<- var2/rm32 var1/r32
17331     0x11/imm32/alloc-id:fake
17332     _string-compare/imm32/name
17333     0x11/imm32/alloc-id:fake
17334     Two-args-int-reg-int-stack/imm32/inouts
17335     0/imm32/no-outputs
17336     0/imm32/no-outputs
17337     0x11/imm32/alloc-id:fake
17338     _string_3b_compare<-/imm32/subx-name
17339     2/imm32/rm32-is-second-inout
17340     1/imm32/r32-is-first-inout
17341     0/imm32/no-imm32
17342     0/imm32/no-imm8
17343     0/imm32/no-disp32
17344     0/imm32/output-is-write-only
17345     0x11/imm32/alloc-id:fake
17346     _Primitive-compare-eax-with-literal/imm32/next
17347 _Primitive-compare-eax-with-literal:  # (payload primitive)
17348     0x11/imm32/alloc-id:fake:payload
17349     # compare var1/eax n => 3d/compare-eax-with n/imm32
17350     0x11/imm32/alloc-id:fake
17351     _string-compare/imm32/name
17352     0x11/imm32/alloc-id:fake
17353     Two-args-int-eax-int-literal/imm32/inouts
17354     0/imm32/no-outputs
17355     0/imm32/no-outputs
17356     0x11/imm32/alloc-id:fake
17357     _string_3d_compare_eax_with/imm32/subx-name
17358     0/imm32/no-rm32
17359     0/imm32/no-r32
17360     2/imm32/imm32-is-second-inout
17361     0/imm32/no-imm8
17362     0/imm32/no-disp32
17363     0/imm32/output-is-write-only
17364     0x11/imm32/alloc-id:fake
17365     _Primitive-compare-reg-with-literal/imm32/next
17366 _Primitive-compare-reg-with-literal:  # (payload primitive)
17367     0x11/imm32/alloc-id:fake:payload
17368     # compare var1/reg n => 81 7/subop/compare %reg n/imm32
17369     0x11/imm32/alloc-id:fake
17370     _string-compare/imm32/name
17371     0x11/imm32/alloc-id:fake
17372     Int-var-in-register-and-literal/imm32/inouts
17373     0/imm32/no-outputs
17374     0/imm32/no-outputs
17375     0x11/imm32/alloc-id:fake
17376     _string_81_subop_compare/imm32/subx-name
17377     1/imm32/rm32-is-first-inout
17378     0/imm32/no-r32
17379     2/imm32/imm32-is-second-inout
17380     0/imm32/no-imm8
17381     0/imm32/no-disp32
17382     0/imm32/output-is-write-only
17383     0x11/imm32/alloc-id:fake
17384     _Primitive-compare-mem-with-literal/imm32/next
17385 _Primitive-compare-mem-with-literal:  # (payload primitive)
17386     0x11/imm32/alloc-id:fake:payload
17387     # compare var1 n => 81 7/subop/compare *(ebp+___) n/imm32
17388     0x11/imm32/alloc-id:fake
17389     _string-compare/imm32/name
17390     0x11/imm32/alloc-id:fake
17391     Int-var-and-literal/imm32/inouts
17392     0/imm32/no-outputs
17393     0/imm32/no-outputs
17394     0x11/imm32/alloc-id:fake
17395     _string_81_subop_compare/imm32/subx-name
17396     1/imm32/rm32-is-first-inout
17397     0/imm32/no-r32
17398     2/imm32/imm32-is-second-inout
17399     0/imm32/no-imm8
17400     0/imm32/no-disp32
17401     0/imm32/output-is-write-only
17402     0x11/imm32/alloc-id:fake
17403     _Primitive-multiply-reg-by-reg/imm32/next
17404 # - multiply
17405 _Primitive-multiply-reg-by-reg:  # (payload primitive)
17406     0x11/imm32/alloc-id:fake:payload
17407     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
17408     0x11/imm32/alloc-id:fake
17409     _string-multiply/imm32/name
17410     0x11/imm32/alloc-id:fake
17411     Single-int-var-in-some-register/imm32/inouts
17412     0x11/imm32/alloc-id:fake
17413     Single-int-var-in-some-register/imm32/outputs
17414     0x11/imm32/alloc-id:fake
17415     _string_0f_af_multiply/imm32/subx-name
17416     1/imm32/rm32-is-first-inout
17417     3/imm32/r32-is-first-output
17418     0/imm32/no-imm32
17419     0/imm32/no-imm8
17420     0/imm32/no-disp32
17421     0/imm32/output-is-write-only
17422     0x11/imm32/alloc-id:fake
17423     _Primitive-multiply-reg-by-mem/imm32/next
17424 _Primitive-multiply-reg-by-mem:  # (payload primitive)
17425     0x11/imm32/alloc-id:fake:payload
17426     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
17427     0x11/imm32/alloc-id:fake
17428     _string-multiply/imm32/name
17429     0x11/imm32/alloc-id:fake
17430     Single-int-var-in-mem/imm32/inouts
17431     0x11/imm32/alloc-id:fake
17432     Single-int-var-in-some-register/imm32/outputs
17433     0x11/imm32/alloc-id:fake
17434     _string_0f_af_multiply/imm32/subx-name
17435     1/imm32/rm32-is-first-inout
17436     3/imm32/r32-is-first-output
17437     0/imm32/no-imm32
17438     0/imm32/no-imm8
17439     0/imm32/no-disp32
17440     0/imm32/output-is-write-only
17441     0x11/imm32/alloc-id:fake
17442     _Primitive-break-if-addr</imm32/next
17443 # - branches
17444 _Primitive-break-if-addr<:  # (payload primitive)
17445     0x11/imm32/alloc-id:fake:payload
17446     0x11/imm32/alloc-id:fake
17447     _string-break-if-addr</imm32/name
17448     0/imm32/no-inouts
17449     0/imm32/no-inouts
17450     0/imm32/no-outputs
17451     0/imm32/no-outputs
17452     0x11/imm32/alloc-id:fake
17453     _string_0f_82_jump_break/imm32/subx-name
17454     0/imm32/no-rm32
17455     0/imm32/no-r32
17456     0/imm32/no-imm32
17457     0/imm32/no-imm8
17458     0/imm32/no-disp32
17459     0/imm32/no-output
17460     0x11/imm32/alloc-id:fake
17461     _Primitive-break-if-addr>=/imm32/next
17462 _Primitive-break-if-addr>=:  # (payload primitive)
17463     0x11/imm32/alloc-id:fake:payload
17464     0x11/imm32/alloc-id:fake
17465     _string-break-if-addr>=/imm32/name
17466     0/imm32/no-inouts
17467     0/imm32/no-inouts
17468     0/imm32/no-outputs
17469     0/imm32/no-outputs
17470     0x11/imm32/alloc-id:fake
17471     _string_0f_83_jump_break/imm32/subx-name
17472     0/imm32/no-rm32
17473     0/imm32/no-r32
17474     0/imm32/no-imm32
17475     0/imm32/no-imm8
17476     0/imm32/no-disp32
17477     0/imm32/no-output
17478     0x11/imm32/alloc-id:fake
17479     _Primitive-break-if-=/imm32/next
17480 _Primitive-break-if-=:  # (payload primitive)
17481     0x11/imm32/alloc-id:fake:payload
17482     0x11/imm32/alloc-id:fake
17483     _string-break-if-=/imm32/name
17484     0/imm32/no-inouts
17485     0/imm32/no-inouts
17486     0/imm32/no-outputs
17487     0/imm32/no-outputs
17488     0x11/imm32/alloc-id:fake
17489     _string_0f_84_jump_break/imm32/subx-name
17490     0/imm32/no-rm32
17491     0/imm32/no-r32
17492     0/imm32/no-imm32
17493     0/imm32/no-imm8
17494     0/imm32/no-disp32
17495     0/imm32/no-output
17496     0x11/imm32/alloc-id:fake
17497     _Primitive-break-if-!=/imm32/next
17498 _Primitive-break-if-!=:  # (payload primitive)
17499     0x11/imm32/alloc-id:fake:payload
17500     0x11/imm32/alloc-id:fake
17501     _string-break-if-!=/imm32/name
17502     0/imm32/no-inouts
17503     0/imm32/no-inouts
17504     0/imm32/no-outputs
17505     0/imm32/no-outputs
17506     0x11/imm32/alloc-id:fake
17507     _string_0f_85_jump_break/imm32/subx-name
17508     0/imm32/no-rm32
17509     0/imm32/no-r32
17510     0/imm32/no-imm32
17511     0/imm32/no-imm8
17512     0/imm32/no-disp32
17513     0/imm32/no-output
17514     0x11/imm32/alloc-id:fake
17515     _Primitive-break-if-addr<=/imm32/next
17516 _Primitive-break-if-addr<=:  # (payload primitive)
17517     0x11/imm32/alloc-id:fake:payload
17518     0x11/imm32/alloc-id:fake
17519     _string-break-if-addr<=/imm32/name
17520     0/imm32/no-inouts
17521     0/imm32/no-inouts
17522     0/imm32/no-outputs
17523     0/imm32/no-outputs
17524     0x11/imm32/alloc-id:fake
17525     _string_0f_86_jump_break/imm32/subx-name
17526     0/imm32/no-rm32
17527     0/imm32/no-r32
17528     0/imm32/no-imm32
17529     0/imm32/no-imm8
17530     0/imm32/no-disp32
17531     0/imm32/no-output
17532     0x11/imm32/alloc-id:fake
17533     _Primitive-break-if-addr>/imm32/next
17534 _Primitive-break-if-addr>:  # (payload primitive)
17535     0x11/imm32/alloc-id:fake:payload
17536     0x11/imm32/alloc-id:fake
17537     _string-break-if-addr>/imm32/name
17538     0/imm32/no-inouts
17539     0/imm32/no-inouts
17540     0/imm32/no-outputs
17541     0/imm32/no-outputs
17542     0x11/imm32/alloc-id:fake
17543     _string_0f_87_jump_break/imm32/subx-name
17544     0/imm32/no-rm32
17545     0/imm32/no-r32
17546     0/imm32/no-imm32
17547     0/imm32/no-imm8
17548     0/imm32/no-disp32
17549     0/imm32/no-output
17550     0x11/imm32/alloc-id:fake
17551     _Primitive-break-if-</imm32/next
17552 _Primitive-break-if-<:  # (payload primitive)
17553     0x11/imm32/alloc-id:fake:payload
17554     0x11/imm32/alloc-id:fake
17555     _string-break-if-</imm32/name
17556     0/imm32/no-inouts
17557     0/imm32/no-inouts
17558     0/imm32/no-outputs
17559     0/imm32/no-outputs
17560     0x11/imm32/alloc-id:fake
17561     _string_0f_8c_jump_break/imm32/subx-name
17562     0/imm32/no-rm32
17563     0/imm32/no-r32
17564     0/imm32/no-imm32
17565     0/imm32/no-imm8
17566     0/imm32/no-disp32
17567     0/imm32/no-output
17568     0x11/imm32/alloc-id:fake
17569     _Primitive-break-if->=/imm32/next
17570 _Primitive-break-if->=:  # (payload primitive)
17571     0x11/imm32/alloc-id:fake:payload
17572     0x11/imm32/alloc-id:fake
17573     _string-break-if->=/imm32/name
17574     0/imm32/no-inouts
17575     0/imm32/no-inouts
17576     0/imm32/no-outputs
17577     0/imm32/no-outputs
17578     0x11/imm32/alloc-id:fake
17579     _string_0f_8d_jump_break/imm32/subx-name
17580     0/imm32/no-rm32
17581     0/imm32/no-r32
17582     0/imm32/no-imm32
17583     0/imm32/no-imm8
17584     0/imm32/no-disp32
17585     0/imm32/no-output
17586     0x11/imm32/alloc-id:fake
17587     _Primitive-break-if-<=/imm32/next
17588 _Primitive-break-if-<=:  # (payload primitive)
17589     0x11/imm32/alloc-id:fake:payload
17590     0x11/imm32/alloc-id:fake
17591     _string-break-if-<=/imm32/name
17592     0/imm32/no-inouts
17593     0/imm32/no-inouts
17594     0/imm32/no-outputs
17595     0/imm32/no-outputs
17596     0x11/imm32/alloc-id:fake
17597     _string_0f_8e_jump_break/imm32/subx-name
17598     0/imm32/no-rm32
17599     0/imm32/no-r32
17600     0/imm32/no-imm32
17601     0/imm32/no-imm8
17602     0/imm32/no-disp32
17603     0/imm32/no-output
17604     0x11/imm32/alloc-id:fake
17605     _Primitive-break-if->/imm32/next
17606 _Primitive-break-if->:  # (payload primitive)
17607     0x11/imm32/alloc-id:fake:payload
17608     0x11/imm32/alloc-id:fake
17609     _string-break-if->/imm32/name
17610     0/imm32/no-inouts
17611     0/imm32/no-inouts
17612     0/imm32/no-outputs
17613     0/imm32/no-outputs
17614     0x11/imm32/alloc-id:fake
17615     _string_0f_8f_jump_break/imm32/subx-name
17616     0/imm32/no-rm32
17617     0/imm32/no-r32
17618     0/imm32/no-imm32
17619     0/imm32/no-imm8
17620     0/imm32/no-disp32
17621     0/imm32/no-output
17622     0x11/imm32/alloc-id:fake
17623     _Primitive-break/imm32/next
17624 _Primitive-break:  # (payload primitive)
17625     0x11/imm32/alloc-id:fake:payload
17626     0x11/imm32/alloc-id:fake
17627     _string-break/imm32/name
17628     0/imm32/no-inouts
17629     0/imm32/no-inouts
17630     0/imm32/no-outputs
17631     0/imm32/no-outputs
17632     0x11/imm32/alloc-id:fake
17633     _string_e9_jump_break/imm32/subx-name
17634     0/imm32/no-rm32
17635     0/imm32/no-r32
17636     0/imm32/no-imm32
17637     0/imm32/no-imm8
17638     0/imm32/no-disp32
17639     0/imm32/no-output
17640     0x11/imm32/alloc-id:fake
17641     _Primitive-loop-if-addr</imm32/next
17642 _Primitive-loop-if-addr<:  # (payload primitive)
17643     0x11/imm32/alloc-id:fake:payload
17644     0x11/imm32/alloc-id:fake
17645     _string-loop-if-addr</imm32/name
17646     0/imm32/no-inouts
17647     0/imm32/no-inouts
17648     0/imm32/no-outputs
17649     0/imm32/no-outputs
17650     0x11/imm32/alloc-id:fake
17651     _string_0f_82_jump_loop/imm32/subx-name
17652     0/imm32/no-rm32
17653     0/imm32/no-r32
17654     0/imm32/no-imm32
17655     0/imm32/no-imm8
17656     0/imm32/no-disp32
17657     0/imm32/no-output
17658     0x11/imm32/alloc-id:fake
17659     _Primitive-loop-if-addr>=/imm32/next
17660 _Primitive-loop-if-addr>=:  # (payload primitive)
17661     0x11/imm32/alloc-id:fake:payload
17662     0x11/imm32/alloc-id:fake
17663     _string-loop-if-addr>=/imm32/name
17664     0/imm32/no-inouts
17665     0/imm32/no-inouts
17666     0/imm32/no-outputs
17667     0/imm32/no-outputs
17668     0x11/imm32/alloc-id:fake
17669     _string_0f_83_jump_loop/imm32/subx-name
17670     0/imm32/no-rm32
17671     0/imm32/no-r32
17672     0/imm32/no-imm32
17673     0/imm32/no-imm8
17674     0/imm32/no-disp32
17675     0/imm32/no-output
17676     0x11/imm32/alloc-id:fake
17677     _Primitive-loop-if-=/imm32/next
17678 _Primitive-loop-if-=:  # (payload primitive)
17679     0x11/imm32/alloc-id:fake:payload
17680     0x11/imm32/alloc-id:fake
17681     _string-loop-if-=/imm32/name
17682     0/imm32/no-inouts
17683     0/imm32/no-inouts
17684     0/imm32/no-outputs
17685     0/imm32/no-outputs
17686     0x11/imm32/alloc-id:fake
17687     _string_0f_84_jump_loop/imm32/subx-name
17688     0/imm32/no-rm32
17689     0/imm32/no-r32
17690     0/imm32/no-imm32
17691     0/imm32/no-imm8
17692     0/imm32/no-disp32
17693     0/imm32/no-output
17694     0x11/imm32/alloc-id:fake
17695     _Primitive-loop-if-!=/imm32/next
17696 _Primitive-loop-if-!=:  # (payload primitive)
17697     0x11/imm32/alloc-id:fake:payload
17698     0x11/imm32/alloc-id:fake
17699     _string-loop-if-!=/imm32/name
17700     0/imm32/no-inouts
17701     0/imm32/no-inouts
17702     0/imm32/no-outputs
17703     0/imm32/no-outputs
17704     0x11/imm32/alloc-id:fake
17705     _string_0f_85_jump_loop/imm32/subx-name
17706     0/imm32/no-rm32
17707     0/imm32/no-r32
17708     0/imm32/no-imm32
17709     0/imm32/no-imm8
17710     0/imm32/no-disp32
17711     0/imm32/no-output
17712     0x11/imm32/alloc-id:fake
17713     _Primitive-loop-if-addr<=/imm32/next
17714 _Primitive-loop-if-addr<=:  # (payload primitive)
17715     0x11/imm32/alloc-id:fake:payload
17716     0x11/imm32/alloc-id:fake
17717     _string-loop-if-addr<=/imm32/name
17718     0/imm32/no-inouts
17719     0/imm32/no-inouts
17720     0/imm32/no-outputs
17721     0/imm32/no-outputs
17722     0x11/imm32/alloc-id:fake
17723     _string_0f_86_jump_loop/imm32/subx-name
17724     0/imm32/no-rm32
17725     0/imm32/no-r32
17726     0/imm32/no-imm32
17727     0/imm32/no-imm8
17728     0/imm32/no-disp32
17729     0/imm32/no-output
17730     0x11/imm32/alloc-id:fake
17731     _Primitive-loop-if-addr>/imm32/next
17732 _Primitive-loop-if-addr>:  # (payload primitive)
17733     0x11/imm32/alloc-id:fake:payload
17734     0x11/imm32/alloc-id:fake
17735     _string-loop-if-addr>/imm32/name
17736     0/imm32/no-inouts
17737     0/imm32/no-inouts
17738     0/imm32/no-outputs
17739     0/imm32/no-outputs
17740     0x11/imm32/alloc-id:fake
17741     _string_0f_87_jump_loop/imm32/subx-name
17742     0/imm32/no-rm32
17743     0/imm32/no-r32
17744     0/imm32/no-imm32
17745     0/imm32/no-imm8
17746     0/imm32/no-disp32
17747     0/imm32/no-output
17748     0x11/imm32/alloc-id:fake
17749     _Primitive-loop-if-</imm32/next
17750 _Primitive-loop-if-<:  # (payload primitive)
17751     0x11/imm32/alloc-id:fake:payload
17752     0x11/imm32/alloc-id:fake
17753     _string-loop-if-</imm32/name
17754     0/imm32/no-inouts
17755     0/imm32/no-inouts
17756     0/imm32/no-outputs
17757     0/imm32/no-outputs
17758     0x11/imm32/alloc-id:fake
17759     _string_0f_8c_jump_loop/imm32/subx-name
17760     0/imm32/no-rm32
17761     0/imm32/no-r32
17762     0/imm32/no-imm32
17763     0/imm32/no-imm8
17764     0/imm32/no-disp32
17765     0/imm32/no-output
17766     0x11/imm32/alloc-id:fake
17767     _Primitive-loop-if->=/imm32/next
17768 _Primitive-loop-if->=:  # (payload primitive)
17769     0x11/imm32/alloc-id:fake:payload
17770     0x11/imm32/alloc-id:fake
17771     _string-loop-if->=/imm32/name
17772     0/imm32/no-inouts
17773     0/imm32/no-inouts
17774     0/imm32/no-outputs
17775     0/imm32/no-outputs
17776     0x11/imm32/alloc-id:fake
17777     _string_0f_8d_jump_loop/imm32/subx-name
17778     0/imm32/no-rm32
17779     0/imm32/no-r32
17780     0/imm32/no-imm32
17781     0/imm32/no-imm8
17782     0/imm32/no-disp32
17783     0/imm32/no-output
17784     0x11/imm32/alloc-id:fake
17785     _Primitive-loop-if-<=/imm32/next
17786 _Primitive-loop-if-<=:  # (payload primitive)
17787     0x11/imm32/alloc-id:fake:payload
17788     0x11/imm32/alloc-id:fake
17789     _string-loop-if-<=/imm32/name
17790     0/imm32/no-inouts
17791     0/imm32/no-inouts
17792     0/imm32/no-outputs
17793     0/imm32/no-outputs
17794     0x11/imm32/alloc-id:fake
17795     _string_0f_8e_jump_loop/imm32/subx-name
17796     0/imm32/no-rm32
17797     0/imm32/no-r32
17798     0/imm32/no-imm32
17799     0/imm32/no-imm8
17800     0/imm32/no-disp32
17801     0/imm32/no-output
17802     0x11/imm32/alloc-id:fake
17803     _Primitive-loop-if->/imm32/next
17804 _Primitive-loop-if->:  # (payload primitive)
17805     0x11/imm32/alloc-id:fake:payload
17806     0x11/imm32/alloc-id:fake
17807     _string-loop-if->/imm32/name
17808     0/imm32/no-inouts
17809     0/imm32/no-inouts
17810     0/imm32/no-outputs
17811     0/imm32/no-outputs
17812     0x11/imm32/alloc-id:fake
17813     _string_0f_8f_jump_loop/imm32/subx-name
17814     0/imm32/no-rm32
17815     0/imm32/no-r32
17816     0/imm32/no-imm32
17817     0/imm32/no-imm8
17818     0/imm32/no-disp32
17819     0/imm32/no-output
17820     0x11/imm32/alloc-id:fake
17821     _Primitive-loop/imm32/next  # we probably don't need an unconditional break
17822 _Primitive-loop:  # (payload primitive)
17823     0x11/imm32/alloc-id:fake:payload
17824     0x11/imm32/alloc-id:fake
17825     _string-loop/imm32/name
17826     0/imm32/no-inouts
17827     0/imm32/no-inouts
17828     0/imm32/no-outputs
17829     0/imm32/no-outputs
17830     0x11/imm32/alloc-id:fake
17831     _string_e9_jump_loop/imm32/subx-name
17832     0/imm32/no-rm32
17833     0/imm32/no-r32
17834     0/imm32/no-imm32
17835     0/imm32/no-imm8
17836     0/imm32/no-disp32
17837     0/imm32/no-output
17838     0x11/imm32/alloc-id:fake
17839     _Primitive-break-if-addr<-named/imm32/next
17840 # - branches to named blocks
17841 _Primitive-break-if-addr<-named:  # (payload primitive)
17842     0x11/imm32/alloc-id:fake:payload
17843     0x11/imm32/alloc-id:fake
17844     _string-break-if-addr</imm32/name
17845     0x11/imm32/alloc-id:fake
17846     Single-lit-var/imm32/inouts
17847     0/imm32/no-outputs
17848     0/imm32/no-outputs
17849     0x11/imm32/alloc-id:fake
17850     _string_0f_82_jump_label/imm32/subx-name
17851     0/imm32/no-rm32
17852     0/imm32/no-r32
17853     0/imm32/no-imm32
17854     0/imm32/no-imm8
17855     1/imm32/disp32-is-first-inout
17856     0/imm32/no-output
17857     0x11/imm32/alloc-id:fake
17858     _Primitive-break-if-addr>=-named/imm32/next
17859 _Primitive-break-if-addr>=-named:  # (payload primitive)
17860     0x11/imm32/alloc-id:fake:payload
17861     0x11/imm32/alloc-id:fake
17862     _string-break-if-addr>=/imm32/name
17863     0x11/imm32/alloc-id:fake
17864     Single-lit-var/imm32/inouts
17865     0/imm32/no-outputs
17866     0/imm32/no-outputs
17867     0x11/imm32/alloc-id:fake
17868     _string_0f_83_jump_label/imm32/subx-name
17869     0/imm32/no-rm32
17870     0/imm32/no-r32
17871     0/imm32/no-imm32
17872     0/imm32/no-imm8
17873     1/imm32/disp32-is-first-inout
17874     0/imm32/no-output
17875     0x11/imm32/alloc-id:fake
17876     _Primitive-break-if-=-named/imm32/next
17877 _Primitive-break-if-=-named:  # (payload primitive)
17878     0x11/imm32/alloc-id:fake:payload
17879     0x11/imm32/alloc-id:fake
17880     _string-break-if-=/imm32/name
17881     0x11/imm32/alloc-id:fake
17882     Single-lit-var/imm32/inouts
17883     0/imm32/no-outputs
17884     0/imm32/no-outputs
17885     0x11/imm32/alloc-id:fake
17886     _string_0f_84_jump_label/imm32/subx-name
17887     0/imm32/no-rm32
17888     0/imm32/no-r32
17889     0/imm32/no-imm32
17890     0/imm32/no-imm8
17891     1/imm32/disp32-is-first-inout
17892     0/imm32/no-output
17893     0x11/imm32/alloc-id:fake
17894     _Primitive-break-if-!=-named/imm32/next
17895 _Primitive-break-if-!=-named:  # (payload primitive)
17896     0x11/imm32/alloc-id:fake:payload
17897     0x11/imm32/alloc-id:fake
17898     _string-break-if-!=/imm32/name
17899     0x11/imm32/alloc-id:fake
17900     Single-lit-var/imm32/inouts
17901     0/imm32/no-outputs
17902     0/imm32/no-outputs
17903     0x11/imm32/alloc-id:fake
17904     _string_0f_85_jump_label/imm32/subx-name
17905     0/imm32/no-rm32
17906     0/imm32/no-r32
17907     0/imm32/no-imm32
17908     0/imm32/no-imm8
17909     1/imm32/disp32-is-first-inout
17910     0/imm32/no-output
17911     0x11/imm32/alloc-id:fake
17912     _Primitive-break-if-addr<=-named/imm32/next
17913 _Primitive-break-if-addr<=-named:  # (payload primitive)
17914     0x11/imm32/alloc-id:fake:payload
17915     0x11/imm32/alloc-id:fake
17916     _string-break-if-addr<=/imm32/name
17917     0x11/imm32/alloc-id:fake
17918     Single-lit-var/imm32/inouts
17919     0/imm32/no-outputs
17920     0/imm32/no-outputs
17921     0x11/imm32/alloc-id:fake
17922     _string_0f_86_jump_label/imm32/subx-name
17923     0/imm32/no-rm32
17924     0/imm32/no-r32
17925     0/imm32/no-imm32
17926     0/imm32/no-imm8
17927     1/imm32/disp32-is-first-inout
17928     0/imm32/no-output
17929     0x11/imm32/alloc-id:fake
17930     _Primitive-break-if-addr>-named/imm32/next
17931 _Primitive-break-if-addr>-named:  # (payload primitive)
17932     0x11/imm32/alloc-id:fake:payload
17933     0x11/imm32/alloc-id:fake
17934     _string-break-if-addr>/imm32/name
17935     0x11/imm32/alloc-id:fake
17936     Single-lit-var/imm32/inouts
17937     0/imm32/no-outputs
17938     0/imm32/no-outputs
17939     0x11/imm32/alloc-id:fake
17940     _string_0f_87_jump_label/imm32/subx-name
17941     0/imm32/no-rm32
17942     0/imm32/no-r32
17943     0/imm32/no-imm32
17944     0/imm32/no-imm8
17945     1/imm32/disp32-is-first-inout
17946     0/imm32/no-output
17947     0x11/imm32/alloc-id:fake
17948     _Primitive-break-if-<-named/imm32/next
17949 _Primitive-break-if-<-named:  # (payload primitive)
17950     0x11/imm32/alloc-id:fake:payload
17951     0x11/imm32/alloc-id:fake
17952     _string-break-if-</imm32/name
17953     0x11/imm32/alloc-id:fake
17954     Single-lit-var/imm32/inouts
17955     0/imm32/no-outputs
17956     0/imm32/no-outputs
17957     0x11/imm32/alloc-id:fake
17958     _string_0f_8c_jump_label/imm32/subx-name
17959     0/imm32/no-rm32
17960     0/imm32/no-r32
17961     0/imm32/no-imm32
17962     0/imm32/no-imm8
17963     1/imm32/disp32-is-first-inout
17964     0/imm32/no-output
17965     0x11/imm32/alloc-id:fake
17966     _Primitive-break-if->=-named/imm32/next
17967 _Primitive-break-if->=-named:  # (payload primitive)
17968     0x11/imm32/alloc-id:fake:payload
17969     0x11/imm32/alloc-id:fake
17970     _string-break-if->=/imm32/name
17971     0x11/imm32/alloc-id:fake
17972     Single-lit-var/imm32/inouts
17973     0/imm32/no-outputs
17974     0/imm32/no-outputs
17975     0x11/imm32/alloc-id:fake
17976     _string_0f_8d_jump_label/imm32/subx-name
17977     0/imm32/no-rm32
17978     0/imm32/no-r32
17979     0/imm32/no-imm32
17980     0/imm32/no-imm8
17981     1/imm32/disp32-is-first-inout
17982     0/imm32/no-output
17983     0x11/imm32/alloc-id:fake
17984     _Primitive-break-if-<=-named/imm32/next
17985 _Primitive-break-if-<=-named:  # (payload primitive)
17986     0x11/imm32/alloc-id:fake:payload
17987     0x11/imm32/alloc-id:fake
17988     _string-break-if-<=/imm32/name
17989     0x11/imm32/alloc-id:fake
17990     Single-lit-var/imm32/inouts
17991     0/imm32/no-outputs
17992     0/imm32/no-outputs
17993     0x11/imm32/alloc-id:fake
17994     _string_0f_8e_jump_label/imm32/subx-name
17995     0/imm32/no-rm32
17996     0/imm32/no-r32
17997     0/imm32/no-imm32
17998     0/imm32/no-imm8
17999     1/imm32/disp32-is-first-inout
18000     0/imm32/no-output
18001     0x11/imm32/alloc-id:fake
18002     _Primitive-break-if->-named/imm32/next
18003 _Primitive-break-if->-named:  # (payload primitive)
18004     0x11/imm32/alloc-id:fake:payload
18005     0x11/imm32/alloc-id:fake
18006     _string-break-if->/imm32/name
18007     0x11/imm32/alloc-id:fake
18008     Single-lit-var/imm32/inouts
18009     0/imm32/no-outputs
18010     0/imm32/no-outputs
18011     0x11/imm32/alloc-id:fake
18012     _string_0f_8f_jump_label/imm32/subx-name
18013     0/imm32/no-rm32
18014     0/imm32/no-r32
18015     0/imm32/no-imm32
18016     0/imm32/no-imm8
18017     1/imm32/disp32-is-first-inout
18018     0/imm32/no-output
18019     0x11/imm32/alloc-id:fake
18020     _Primitive-break-named/imm32/next
18021 _Primitive-break-named:  # (payload primitive)
18022     0x11/imm32/alloc-id:fake:payload
18023     0x11/imm32/alloc-id:fake
18024     _string-break/imm32/name
18025     0x11/imm32/alloc-id:fake
18026     Single-lit-var/imm32/inouts
18027     0/imm32/no-outputs
18028     0/imm32/no-outputs
18029     0x11/imm32/alloc-id:fake
18030     _string_e9_jump_label/imm32/subx-name
18031     0/imm32/no-rm32
18032     0/imm32/no-r32
18033     0/imm32/no-imm32
18034     0/imm32/no-imm8
18035     1/imm32/disp32-is-first-inout
18036     0/imm32/no-output
18037     0x11/imm32/alloc-id:fake
18038     _Primitive-loop-if-addr<-named/imm32/next
18039 _Primitive-loop-if-addr<-named:  # (payload primitive)
18040     0x11/imm32/alloc-id:fake:payload
18041     0x11/imm32/alloc-id:fake
18042     _string-loop-if-addr</imm32/name
18043     0x11/imm32/alloc-id:fake
18044     Single-lit-var/imm32/inouts
18045     0/imm32/no-outputs
18046     0/imm32/no-outputs
18047     0x11/imm32/alloc-id:fake
18048     _string_0f_82_jump_label/imm32/subx-name
18049     0/imm32/no-rm32
18050     0/imm32/no-r32
18051     0/imm32/no-imm32
18052     0/imm32/no-imm8
18053     1/imm32/disp32-is-first-inout
18054     0/imm32/no-output
18055     0x11/imm32/alloc-id:fake
18056     _Primitive-loop-if-addr>=-named/imm32/next
18057 _Primitive-loop-if-addr>=-named:  # (payload primitive)
18058     0x11/imm32/alloc-id:fake:payload
18059     0x11/imm32/alloc-id:fake
18060     _string-loop-if-addr>=/imm32/name
18061     0x11/imm32/alloc-id:fake
18062     Single-lit-var/imm32/inouts
18063     0/imm32/no-outputs
18064     0/imm32/no-outputs
18065     0x11/imm32/alloc-id:fake
18066     _string_0f_83_jump_label/imm32/subx-name
18067     0/imm32/no-rm32
18068     0/imm32/no-r32
18069     0/imm32/no-imm32
18070     0/imm32/no-imm8
18071     1/imm32/disp32-is-first-inout
18072     0/imm32/no-output
18073     0x11/imm32/alloc-id:fake
18074     _Primitive-loop-if-=-named/imm32/next
18075 _Primitive-loop-if-=-named:  # (payload primitive)
18076     0x11/imm32/alloc-id:fake:payload
18077     0x11/imm32/alloc-id:fake
18078     _string-loop-if-=/imm32/name
18079     0x11/imm32/alloc-id:fake
18080     Single-lit-var/imm32/inouts
18081     0/imm32/no-outputs
18082     0/imm32/no-outputs
18083     0x11/imm32/alloc-id:fake
18084     _string_0f_84_jump_label/imm32/subx-name
18085     0/imm32/no-rm32
18086     0/imm32/no-r32
18087     0/imm32/no-imm32
18088     0/imm32/no-imm8
18089     1/imm32/disp32-is-first-inout
18090     0/imm32/no-output
18091     0x11/imm32/alloc-id:fake
18092     _Primitive-loop-if-!=-named/imm32/next
18093 _Primitive-loop-if-!=-named:  # (payload primitive)
18094     0x11/imm32/alloc-id:fake:payload
18095     0x11/imm32/alloc-id:fake
18096     _string-loop-if-!=/imm32/name
18097     0x11/imm32/alloc-id:fake
18098     Single-lit-var/imm32/inouts
18099     0/imm32/no-outputs
18100     0/imm32/no-outputs
18101     0x11/imm32/alloc-id:fake
18102     _string_0f_85_jump_label/imm32/subx-name
18103     0/imm32/no-rm32
18104     0/imm32/no-r32
18105     0/imm32/no-imm32
18106     0/imm32/no-imm8
18107     1/imm32/disp32-is-first-inout
18108     0/imm32/no-output
18109     0x11/imm32/alloc-id:fake
18110     _Primitive-loop-if-addr<=-named/imm32/next
18111 _Primitive-loop-if-addr<=-named:  # (payload primitive)
18112     0x11/imm32/alloc-id:fake:payload
18113     0x11/imm32/alloc-id:fake
18114     _string-loop-if-addr<=/imm32/name
18115     0x11/imm32/alloc-id:fake
18116     Single-lit-var/imm32/inouts
18117     0/imm32/no-outputs
18118     0/imm32/no-outputs
18119     0x11/imm32/alloc-id:fake
18120     _string_0f_86_jump_label/imm32/subx-name
18121     0/imm32/no-rm32
18122     0/imm32/no-r32
18123     0/imm32/no-imm32
18124     0/imm32/no-imm8
18125     1/imm32/disp32-is-first-inout
18126     0/imm32/no-output
18127     0x11/imm32/alloc-id:fake
18128     _Primitive-loop-if-addr>-named/imm32/next
18129 _Primitive-loop-if-addr>-named:  # (payload primitive)
18130     0x11/imm32/alloc-id:fake:payload
18131     0x11/imm32/alloc-id:fake
18132     _string-loop-if-addr>/imm32/name
18133     0x11/imm32/alloc-id:fake
18134     Single-lit-var/imm32/inouts
18135     0/imm32/no-outputs
18136     0/imm32/no-outputs
18137     0x11/imm32/alloc-id:fake
18138     _string_0f_87_jump_label/imm32/subx-name
18139     0/imm32/no-rm32
18140     0/imm32/no-r32
18141     0/imm32/no-imm32
18142     0/imm32/no-imm8
18143     1/imm32/disp32-is-first-inout
18144     0/imm32/no-output
18145     0x11/imm32/alloc-id:fake
18146     _Primitive-loop-if-<-named/imm32/next
18147 _Primitive-loop-if-<-named:  # (payload primitive)
18148     0x11/imm32/alloc-id:fake:payload
18149     0x11/imm32/alloc-id:fake
18150     _string-loop-if-</imm32/name
18151     0x11/imm32/alloc-id:fake
18152     Single-lit-var/imm32/inouts
18153     0/imm32/no-outputs
18154     0/imm32/no-outputs
18155     0x11/imm32/alloc-id:fake
18156     _string_0f_8c_jump_label/imm32/subx-name
18157     0/imm32/no-rm32
18158     0/imm32/no-r32
18159     0/imm32/no-imm32
18160     0/imm32/no-imm8
18161     1/imm32/disp32-is-first-inout
18162     0/imm32/no-output
18163     0x11/imm32/alloc-id:fake
18164     _Primitive-loop-if->=-named/imm32/next
18165 _Primitive-loop-if->=-named:  # (payload primitive)
18166     0x11/imm32/alloc-id:fake:payload
18167     0x11/imm32/alloc-id:fake
18168     _string-loop-if->=/imm32/name
18169     0x11/imm32/alloc-id:fake
18170     Single-lit-var/imm32/inouts
18171     0/imm32/no-outputs
18172     0/imm32/no-outputs
18173     0x11/imm32/alloc-id:fake
18174     _string_0f_8d_jump_label/imm32/subx-name
18175     0/imm32/no-rm32
18176     0/imm32/no-r32
18177     0/imm32/no-imm32
18178     0/imm32/no-imm8
18179     1/imm32/disp32-is-first-inout
18180     0/imm32/no-output
18181     0x11/imm32/alloc-id:fake
18182     _Primitive-loop-if-<=-named/imm32/next
18183 _Primitive-loop-if-<=-named:  # (payload primitive)
18184     0x11/imm32/alloc-id:fake:payload
18185     0x11/imm32/alloc-id:fake
18186     _string-loop-if-<=/imm32/name
18187     0x11/imm32/alloc-id:fake
18188     Single-lit-var/imm32/inouts
18189     0/imm32/no-outputs
18190     0/imm32/no-outputs
18191     0x11/imm32/alloc-id:fake
18192     _string_0f_8e_jump_label/imm32/subx-name
18193     0/imm32/no-rm32
18194     0/imm32/no-r32
18195     0/imm32/no-imm32
18196     0/imm32/no-imm8
18197     1/imm32/disp32-is-first-inout
18198     0/imm32/no-output
18199     0x11/imm32/alloc-id:fake
18200     _Primitive-loop-if->-named/imm32/next
18201 _Primitive-loop-if->-named:  # (payload primitive)
18202     0x11/imm32/alloc-id:fake:payload
18203     0x11/imm32/alloc-id:fake
18204     _string-loop-if->/imm32/name
18205     0x11/imm32/alloc-id:fake
18206     Single-lit-var/imm32/inouts
18207     0/imm32/no-outputs
18208     0/imm32/no-outputs
18209     0x11/imm32/alloc-id:fake
18210     _string_0f_8f_jump_label/imm32/subx-name
18211     0/imm32/no-rm32
18212     0/imm32/no-r32
18213     0/imm32/no-imm32
18214     0/imm32/no-imm8
18215     1/imm32/disp32-is-first-inout
18216     0/imm32/no-output
18217     0x11/imm32/alloc-id:fake
18218     _Primitive-loop-named/imm32/next  # we probably don't need an unconditional break
18219 _Primitive-loop-named:  # (payload primitive)
18220     0x11/imm32/alloc-id:fake:payload
18221     0x11/imm32/alloc-id:fake
18222     _string-loop/imm32/name
18223     0x11/imm32/alloc-id:fake
18224     Single-lit-var/imm32/inouts
18225     0/imm32/no-outputs
18226     0/imm32/no-outputs
18227     0x11/imm32/alloc-id:fake
18228     _string_e9_jump_label/imm32/subx-name
18229     0/imm32/no-rm32
18230     0/imm32/no-r32
18231     0/imm32/no-imm32
18232     0/imm32/no-imm8
18233     1/imm32/disp32-is-first-inout
18234     0/imm32/no-output
18235     0/imm32/next
18236     0/imm32/next
18237 
18238 # string literals for Mu instructions
18239 _string-add:  # (payload array byte)
18240     0x11/imm32/alloc-id:fake:payload
18241     # "add"
18242     0x3/imm32/size
18243     0x61/a 0x64/d 0x64/d
18244 _string-address:  # (payload array byte)
18245     0x11/imm32/alloc-id:fake:payload
18246     # "address"
18247     0x7/imm32/size
18248     0x61/a 0x64/d 0x64/d 0x72/r 0x65/e 0x73/s 0x73/s
18249 _string-add-to:  # (payload array byte)
18250     0x11/imm32/alloc-id:fake:payload
18251     # "add-to"
18252     0x6/imm32/size
18253     0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
18254 _string-and:  # (payload array byte)
18255     0x11/imm32/alloc-id:fake:payload
18256     # "and"
18257     0x3/imm32/size
18258     0x61/a 0x6e/n 0x64/d
18259 _string-and-with:  # (payload array byte)
18260     0x11/imm32/alloc-id:fake:payload
18261     # "and-with"
18262     0x8/imm32/size
18263     0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
18264 _string-break:  # (payload array byte)
18265     0x11/imm32/alloc-id:fake:payload
18266     # "break"
18267     0x5/imm32/size
18268     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k
18269 _string-break-if-<:  # (payload array byte)
18270     0x11/imm32/alloc-id:fake:payload
18271     # "break-if-<"
18272     0xa/imm32/size
18273     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
18274 _string-break-if-<=:  # (payload array byte)
18275     0x11/imm32/alloc-id:fake:payload
18276     # "break-if-<="
18277     0xb/imm32/size
18278     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
18279 _string-break-if-=:  # (payload array byte)
18280     0x11/imm32/alloc-id:fake:payload
18281     # "break-if-="
18282     0xa/imm32/size
18283     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
18284 _string-break-if->:  # (payload array byte)
18285     0x11/imm32/alloc-id:fake:payload
18286     # "break-if->"
18287     0xa/imm32/size
18288     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
18289 _string-break-if->=:  # (payload array byte)
18290     0x11/imm32/alloc-id:fake:payload
18291     # "break-if->="
18292     0xb/imm32/size
18293     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
18294 _string-break-if-!=:  # (payload array byte)
18295     0x11/imm32/alloc-id:fake:payload
18296     # "break-if-!="
18297     0xb/imm32/size
18298     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
18299 _string-break-if-addr<:  # (payload array byte)
18300     0x11/imm32/alloc-id:fake:payload
18301     # "break-if-addr<"
18302     0xe/imm32/size
18303     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/<
18304 _string-break-if-addr<=:  # (payload array byte)
18305     0x11/imm32/alloc-id:fake:payload
18306     # "break-if-addr<="
18307     0xf/imm32/size
18308     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/=
18309 _string-break-if-addr>:  # (payload array byte)
18310     0x11/imm32/alloc-id:fake:payload
18311     # "break-if-addr>"
18312     0xe/imm32/size
18313     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/>
18314 _string-break-if-addr>=:  # (payload array byte)
18315     0x11/imm32/alloc-id:fake:payload
18316     # "break-if-addr>="
18317     0xf/imm32/size
18318     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/=
18319 _string-compare:  # (payload array byte)
18320     0x11/imm32/alloc-id:fake:payload
18321     # "compare"
18322     0x7/imm32/size
18323     0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e
18324 _string-copy:  # (payload array byte)
18325     0x11/imm32/alloc-id:fake:payload
18326     # "copy"
18327     0x4/imm32/size
18328     0x63/c 0x6f/o 0x70/p 0x79/y
18329 _string-copy-to:  # (payload array byte)
18330     0x11/imm32/alloc-id:fake:payload
18331     # "copy-to"
18332     0x7/imm32/size
18333     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o
18334 _string-copy-byte:
18335     0x11/imm32/alloc-id:fake:payload
18336     # "copy-byte"
18337     0x9/imm32/size
18338     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e
18339 _string-copy-byte-to:
18340     0x11/imm32/alloc-id:fake:payload
18341     # "copy-byte-to"
18342     0xc/imm32/size
18343     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x74/t 0x6f/o
18344 _string-decrement:  # (payload array byte)
18345     0x11/imm32/alloc-id:fake:payload
18346     # "decrement"
18347     0x9/imm32/size
18348     0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
18349 _string-increment:  # (payload array byte)
18350     0x11/imm32/alloc-id:fake:payload
18351     # "increment"
18352     0x9/imm32/size
18353     0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
18354 _string-loop:  # (payload array byte)
18355     0x11/imm32/alloc-id:fake:payload
18356     # "loop"
18357     0x4/imm32/size
18358     0x6c/l 0x6f/o 0x6f/o 0x70/p
18359 _string-loop-if-<:  # (payload array byte)
18360     0x11/imm32/alloc-id:fake:payload
18361     # "loop-if-<"
18362     0x9/imm32/size
18363     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
18364 _string-loop-if-<=:  # (payload array byte)
18365     0x11/imm32/alloc-id:fake:payload
18366     # "loop-if-<="
18367     0xa/imm32/size
18368     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
18369 _string-loop-if-=:  # (payload array byte)
18370     0x11/imm32/alloc-id:fake:payload
18371     # "loop-if-="
18372     0x9/imm32/size
18373     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
18374 _string-loop-if->:  # (payload array byte)
18375     0x11/imm32/alloc-id:fake:payload
18376     # "loop-if->"
18377     0x9/imm32/size
18378     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
18379 _string-loop-if->=:  # (payload array byte)
18380     0x11/imm32/alloc-id:fake:payload
18381     # "loop-if->="
18382     0xa/imm32/size
18383     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
18384 _string-loop-if-!=:  # (payload array byte)
18385     0x11/imm32/alloc-id:fake:payload
18386     # "loop-if-!="
18387     0xa/imm32/size
18388     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
18389 _string-loop-if-addr<:  # (payload array byte)
18390     0x11/imm32/alloc-id:fake:payload
18391     # "loop-if-addr<"
18392     0xd/imm32/size
18393     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/<
18394 _string-loop-if-addr<=:  # (payload array byte)
18395     0x11/imm32/alloc-id:fake:payload
18396     # "loop-if-addr<="
18397     0xe/imm32/size
18398     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/=
18399 _string-loop-if-addr>:  # (payload array byte)
18400     0x11/imm32/alloc-id:fake:payload
18401     # "loop-if-addr>"
18402     0xd/imm32/size
18403     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/>
18404 _string-loop-if-addr>=:  # (payload array byte)
18405     0x11/imm32/alloc-id:fake:payload
18406     # "loop-if-addr>="
18407     0xe/imm32/size
18408     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/=
18409 _string-multiply:  # (payload array byte)
18410     0x11/imm32/alloc-id:fake:payload
18411     # "multiply"
18412     0x8/imm32/size
18413     0x6d/m 0x75/u 0x6c/l 0x74/t 0x69/i 0x70/p 0x6c/l 0x79/y
18414 _string-or:  # (payload array byte)
18415     0x11/imm32/alloc-id:fake:payload
18416     # "or"
18417     0x2/imm32/size
18418     0x6f/o 0x72/r
18419 _string-or-with:  # (payload array byte)
18420     0x11/imm32/alloc-id:fake:payload
18421     # "or-with"
18422     0x7/imm32/size
18423     0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
18424 _string-subtract:  # (payload array byte)
18425     0x11/imm32/alloc-id:fake:payload
18426     # "subtract"
18427     0x8/imm32/size
18428     0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
18429 _string-subtract-from:  # (payload array byte)
18430     0x11/imm32/alloc-id:fake:payload
18431     # "subtract-from"
18432     0xd/imm32/size
18433     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
18434 _string-xor:  # (payload array byte)
18435     0x11/imm32/alloc-id:fake:payload
18436     # "xor"
18437     0x3/imm32/size
18438     0x78/x 0x6f/o 0x72/r
18439 _string-xor-with:  # (payload array byte)
18440     0x11/imm32/alloc-id:fake:payload
18441     # "xor-with"
18442     0x8/imm32/size
18443     0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
18444 _string-shift-left:  # (payload array byte)
18445     0x11/imm32/alloc-id:fake:payload
18446     # "shift-left"
18447     0xa/imm32/size
18448     0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x2d/dash 0x6c/l 0x65/e 0x66/f 0x74/t
18449 _string-shift-right:  # (payload array byte)
18450     0x11/imm32/alloc-id:fake:payload
18451     # "shift-right"
18452     0xb/imm32/size
18453     0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x2d/dash 0x72/r 0x69/i 0x67/g 0x68/h 0x74/t
18454 _string-shift-right-signed:  # (payload array byte)
18455     0x11/imm32/alloc-id:fake:payload
18456     # "shift-right-signed"
18457     0x12/imm32/size
18458     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
18459 
18460 # string literals for SubX instructions
18461 _string_01_add_to:  # (payload array byte)
18462     0x11/imm32/alloc-id:fake:payload
18463     # "01/add-to"
18464     0x9/imm32/size
18465     0x30/0 0x31/1 0x2f/slash 0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
18466 _string_03_add:  # (payload array byte)
18467     0x11/imm32/alloc-id:fake:payload
18468     # "03/add"
18469     0x6/imm32/size
18470     0x30/0 0x33/3 0x2f/slash 0x61/a 0x64/d 0x64/d
18471 _string_05_add_to_eax:  # (payload array byte)
18472     0x11/imm32/alloc-id:fake:payload
18473     # "05/add-to-eax"
18474     0xd/imm32/size
18475     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
18476 _string_09_or_with:  # (payload array byte)
18477     0x11/imm32/alloc-id:fake:payload
18478     # "09/or-with"
18479     0xa/imm32/size
18480     0x30/0 0x39/9 0x2f/slash 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
18481 _string_0b_or:  # (payload array byte)
18482     0x11/imm32/alloc-id:fake:payload
18483     # "0b/or"
18484     0x5/imm32/size
18485     0x30/0 0x62/b 0x2f/slash 0x6f/o 0x72/r
18486 _string_0d_or_with_eax:  # (payload array byte)
18487     0x11/imm32/alloc-id:fake:payload
18488     # "0d/or-with-eax"
18489     0xe/imm32/size
18490     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
18491 _string_0f_82_jump_label:  # (payload array byte)
18492     0x11/imm32/alloc-id:fake:payload
18493     # "0f 82/jump-if-addr<"
18494     0x13/imm32/size
18495     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/<
18496 _string_0f_82_jump_break:  # (payload array byte)
18497     0x11/imm32/alloc-id:fake:payload
18498     # "0f 82/jump-if-addr< break/disp32"
18499     0x20/imm32/size
18500     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
18501 _string_0f_82_jump_loop:  # (payload array byte)
18502     0x11/imm32/alloc-id:fake:payload
18503     # "0f 82/jump-if-addr< loop/disp32"
18504     0x1f/imm32/size
18505     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
18506 _string_0f_83_jump_label:  # (payload array byte)
18507     0x11/imm32/alloc-id:fake:payload
18508     # "0f 83/jump-if-addr>="
18509     0x14/imm32/size
18510     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/=
18511 _string_0f_83_jump_break:  # (payload array byte)
18512     0x11/imm32/alloc-id:fake:payload
18513     # "0f 83/jump-if-addr>= break/disp32"
18514     0x21/imm32/size
18515     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
18516 _string_0f_83_jump_loop:  # (payload array byte)
18517     0x11/imm32/alloc-id:fake:payload
18518     # "0f 83/jump-if-addr>= loop/disp32"
18519     0x20/imm32/size
18520     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
18521 _string_0f_84_jump_label:  # (payload array byte)
18522     0x11/imm32/alloc-id:fake:payload
18523     # "0f 84/jump-if-="
18524     0xf/imm32/size
18525     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/=
18526 _string_0f_84_jump_break:  # (payload array byte)
18527     0x11/imm32/alloc-id:fake:payload
18528     # "0f 84/jump-if-= break/disp32"
18529     0x1c/imm32/size
18530     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
18531 _string_0f_84_jump_loop:  # (payload array byte)
18532     0x11/imm32/alloc-id:fake:payload
18533     # "0f 84/jump-if-= loop/disp32"
18534     0x1b/imm32/size
18535     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
18536 _string_0f_85_jump_label:  # (payload array byte)
18537     0x11/imm32/alloc-id:fake:payload
18538     # "0f 85/jump-if-!="
18539     0x10/imm32/size
18540     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/=
18541 _string_0f_85_jump_break:  # (payload array byte)
18542     0x11/imm32/alloc-id:fake:payload
18543     # "0f 85/jump-if-!= break/disp32"
18544     0x1d/imm32/size
18545     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
18546 _string_0f_85_jump_loop:  # (payload array byte)
18547     0x11/imm32/alloc-id:fake:payload
18548     # "0f 85/jump-if-!= loop/disp32"
18549     0x1c/imm32/size
18550     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
18551 _string_0f_86_jump_label:  # (payload array byte)
18552     0x11/imm32/alloc-id:fake:payload
18553     # "0f 86/jump-if-addr<="
18554     0x14/imm32/size
18555     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/=
18556 _string_0f_86_jump_break:  # (payload array byte)
18557     0x11/imm32/alloc-id:fake:payload
18558     # "0f 86/jump-if-addr<= break/disp32"
18559     0x21/imm32/size
18560     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
18561 _string_0f_86_jump_loop:  # (payload array byte)
18562     0x11/imm32/alloc-id:fake:payload
18563     # "0f 86/jump-if-addr<= loop/disp32"
18564     0x20/imm32/size
18565     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
18566 _string_0f_87_jump_label:  # (payload array byte)
18567     0x11/imm32/alloc-id:fake:payload
18568     # "0f 87/jump-if-addr>"
18569     0x13/imm32/size
18570     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/>
18571 _string_0f_87_jump_break:  # (payload array byte)
18572     0x11/imm32/alloc-id:fake:payload
18573     # "0f 87/jump-if-addr> break/disp32"
18574     0x20/imm32/size
18575     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
18576 _string_0f_87_jump_loop:  # (payload array byte)
18577     0x11/imm32/alloc-id:fake:payload
18578     # "0f 87/jump-if-addr> loop/disp32"
18579     0x1f/imm32/size
18580     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
18581 _string_0f_8c_jump_label:  # (payload array byte)
18582     0x11/imm32/alloc-id:fake:payload
18583     # "0f 8c/jump-if-<"
18584     0xf/imm32/size
18585     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/<
18586 _string_0f_8c_jump_break:  # (payload array byte)
18587     0x11/imm32/alloc-id:fake:payload
18588     # "0f 8c/jump-if-< break/disp32"
18589     0x1c/imm32/size
18590     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
18591 _string_0f_8c_jump_loop:  # (payload array byte)
18592     0x11/imm32/alloc-id:fake:payload
18593     # "0f 8c/jump-if-< loop/disp32"
18594     0x1b/imm32/size
18595     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
18596 _string_0f_8d_jump_label:  # (payload array byte)
18597     0x11/imm32/alloc-id:fake:payload
18598     # "0f 8d/jump-if->="
18599     0x10/imm32/size
18600     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/=
18601 _string_0f_8d_jump_break:  # (payload array byte)
18602     0x11/imm32/alloc-id:fake:payload
18603     # "0f 8d/jump-if->= break/disp32"
18604     0x1d/imm32/size
18605     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
18606 _string_0f_8d_jump_loop:  # (payload array byte)
18607     0x11/imm32/alloc-id:fake:payload
18608     # "0f 8d/jump-if->= loop/disp32"
18609     0x1c/imm32/size
18610     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
18611 _string_0f_8e_jump_label:  # (payload array byte)
18612     0x11/imm32/alloc-id:fake:payload
18613     # "0f 8e/jump-if-<="
18614     0x10/imm32/size
18615     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/=
18616 _string_0f_8e_jump_break:  # (payload array byte)
18617     0x11/imm32/alloc-id:fake:payload
18618     # "0f 8e/jump-if-<= break/disp32"
18619     0x1d/imm32/size
18620     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
18621 _string_0f_8e_jump_loop:  # (payload array byte)
18622     0x11/imm32/alloc-id:fake:payload
18623     # "0f 8e/jump-if-<= loop/disp32"
18624     0x1c/imm32/size
18625     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
18626 _string_0f_8f_jump_label:  # (payload array byte)
18627     0x11/imm32/alloc-id:fake:payload
18628     # "0f 8f/jump-if->"
18629     0xf/imm32/size
18630     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/>
18631 _string_0f_8f_jump_break:  # (payload array byte)
18632     0x11/imm32/alloc-id:fake:payload
18633     # "0f 8f/jump-if-> break/disp32"
18634     0x1c/imm32/size
18635     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
18636 _string_0f_8f_jump_loop:  # (payload array byte)
18637     0x11/imm32/alloc-id:fake:payload
18638     # "0f 8f/jump-if-> loop/disp32"
18639     0x1b/imm32/size
18640     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
18641 _string_0f_af_multiply:  # (payload array byte)
18642     0x11/imm32/alloc-id:fake:payload
18643     # "0f af/multiply"
18644     0xe/imm32/size
18645     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
18646 _string_21_and_with:  # (payload array byte)
18647     0x11/imm32/alloc-id:fake:payload
18648     # "21/and-with"
18649     0xb/imm32/size
18650     0x32/2 0x31/1 0x2f/slash 0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
18651 _string_23_and:  # (payload array byte)
18652     0x11/imm32/alloc-id:fake:payload
18653     # "23/and"
18654     0x6/imm32/size
18655     0x32/2 0x33/3 0x2f/slash 0x61/a 0x6e/n 0x64/d
18656 _string_25_and_with_eax:  # (payload array byte)
18657     0x11/imm32/alloc-id:fake:payload
18658     # "25/and-with-eax"
18659     0xf/imm32/size
18660     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
18661 _string_29_subtract_from:  # (payload array byte)
18662     0x11/imm32/alloc-id:fake:payload
18663     # "29/subtract-from"
18664     0x10/imm32/size
18665     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
18666 _string_2b_subtract:  # (payload array byte)
18667     0x11/imm32/alloc-id:fake:payload
18668     # "2b/subtract"
18669     0xb/imm32/size
18670     0x32/2 0x62/b 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
18671 _string_2d_subtract_from_eax:  # (payload array byte)
18672     0x11/imm32/alloc-id:fake:payload
18673     # "2d/subtract-from-eax"
18674     0x14/imm32/size
18675     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
18676 _string_31_xor_with:  # (payload array byte)
18677     0x11/imm32/alloc-id:fake:payload
18678     # "31/xor-with"
18679     0xb/imm32/size
18680     0x33/3 0x31/1 0x2f/slash 0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
18681 _string_33_xor:  # (payload array byte)
18682     0x11/imm32/alloc-id:fake:payload
18683     # "33/xor"
18684     0x6/imm32/size
18685     0x33/3 0x33/3 0x2f/slash 0x78/x 0x6f/o 0x72/r
18686 _string_35_xor_with_eax:  # (payload array byte)
18687     0x11/imm32/alloc-id:fake:payload
18688     # "35/xor-with-eax"
18689     0xf/imm32/size
18690     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
18691 _string_39_compare->:  # (payload array byte)
18692     0x11/imm32/alloc-id:fake:payload
18693     # "39/compare->"
18694     0xc/imm32/size
18695     0x33/3 0x39/9 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x2d/dash 0x3e/>
18696 _string_3b_compare<-:  # (payload array byte)
18697     0x11/imm32/alloc-id:fake:payload
18698     # "3b/compare<-"
18699     0xc/imm32/size
18700     0x33/3 0x62/b 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x3c/< 0x2d/dash
18701 _string_3d_compare_eax_with:  # (payload array byte)
18702     0x11/imm32/alloc-id:fake:payload
18703     # "3d/compare-eax-with"
18704     0x13/imm32/size
18705     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
18706 _string_40_increment_eax:  # (payload array byte)
18707     0x11/imm32/alloc-id:fake:payload
18708     # "40/increment-eax"
18709     0x10/imm32/size
18710     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
18711 _string_41_increment_ecx:  # (payload array byte)
18712     0x11/imm32/alloc-id:fake:payload
18713     # "41/increment-ecx"
18714     0x10/imm32/size
18715     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
18716 _string_42_increment_edx:  # (payload array byte)
18717     0x11/imm32/alloc-id:fake:payload
18718     # "42/increment-edx"
18719     0x10/imm32/size
18720     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
18721 _string_43_increment_ebx:  # (payload array byte)
18722     0x11/imm32/alloc-id:fake:payload
18723     # "43/increment-ebx"
18724     0x10/imm32/size
18725     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
18726 _string_46_increment_esi:  # (payload array byte)
18727     0x11/imm32/alloc-id:fake:payload
18728     # "46/increment-esi"
18729     0x10/imm32/size
18730     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
18731 _string_47_increment_edi:  # (payload array byte)
18732     0x11/imm32/alloc-id:fake:payload
18733     # "47/increment-edi"
18734     0x10/imm32/size
18735     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
18736 _string_48_decrement_eax:  # (payload array byte)
18737     0x11/imm32/alloc-id:fake:payload
18738     # "48/decrement-eax"
18739     0x10/imm32/size
18740     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
18741 _string_49_decrement_ecx:  # (payload array byte)
18742     0x11/imm32/alloc-id:fake:payload
18743     # "49/decrement-ecx"
18744     0x10/imm32/size
18745     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
18746 _string_4a_decrement_edx:  # (payload array byte)
18747     0x11/imm32/alloc-id:fake:payload
18748     # "4a/decrement-edx"
18749     0x10/imm32/size
18750     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
18751 _string_4b_decrement_ebx:  # (payload array byte)
18752     0x11/imm32/alloc-id:fake:payload
18753     # "4b/decrement-ebx"
18754     0x10/imm32/size
18755     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
18756 _string_4e_decrement_esi:  # (payload array byte)
18757     0x11/imm32/alloc-id:fake:payload
18758     # "4e/decrement-esi"
18759     0x10/imm32/size
18760     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
18761 _string_4f_decrement_edi:  # (payload array byte)
18762     0x11/imm32/alloc-id:fake:payload
18763     # "4f/decrement-edi"
18764     0x10/imm32/size
18765     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
18766 _string_81_subop_add:  # (payload array byte)
18767     0x11/imm32/alloc-id:fake:payload
18768     # "81 0/subop/add"
18769     0xe/imm32/size
18770     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
18771 _string_81_subop_or:  # (payload array byte)
18772     0x11/imm32/alloc-id:fake:payload
18773     # "81 1/subop/or"
18774     0xd/imm32/size
18775     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
18776 _string_81_subop_and:  # (payload array byte)
18777     0x11/imm32/alloc-id:fake:payload
18778     # "81 4/subop/and"
18779     0xe/imm32/size
18780     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
18781 _string_81_subop_subtract:  # (payload array byte)
18782     0x11/imm32/alloc-id:fake:payload
18783     # "81 5/subop/subtract"
18784     0x13/imm32/size
18785     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
18786 _string_81_subop_xor:  # (payload array byte)
18787     0x11/imm32/alloc-id:fake:payload
18788     # "81 6/subop/xor"
18789     0xe/imm32/size
18790     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
18791 _string_81_subop_compare:  # (payload array byte)
18792     0x11/imm32/alloc-id:fake:payload
18793     # "81 7/subop/compare"
18794     0x12/imm32/size
18795     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
18796 _string_89_<-:  # (payload array byte)
18797     0x11/imm32/alloc-id:fake:payload
18798     # "89/<-"
18799     0x5/imm32/size
18800     0x38/8 0x39/9 0x2f/slash 0x3c/< 0x2d/dash
18801 _string_8b_->:  # (payload array byte)
18802     0x11/imm32/alloc-id:fake:payload
18803     # "8b/->"
18804     0x5/imm32/size
18805     0x38/8 0x62/b 0x2f/slash 0x2d/dash 0x3e/>
18806 _string_8a_copy_byte:
18807     0x11/imm32/alloc-id:fake:payload
18808     # "8a/byte->"
18809     0x9/imm32/size
18810     0x38/8 0x61/a 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x3e/>
18811 _string_88_copy_byte:
18812     0x11/imm32/alloc-id:fake:payload
18813     # "88/byte<-"
18814     0x9/imm32/size
18815     0x38/8 0x38/8 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x3c/< 0x2d/-
18816 _string_8d_copy_address:  # (payload array byte)
18817     0x11/imm32/alloc-id:fake:payload
18818     # "8d/copy-address"
18819     0xf/imm32/size
18820     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
18821 _string_b8_copy_to_eax:  # (payload array byte)
18822     0x11/imm32/alloc-id:fake:payload
18823     # "b8/copy-to-eax"
18824     0xe/imm32/size
18825     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
18826 _string_b9_copy_to_ecx:  # (payload array byte)
18827     0x11/imm32/alloc-id:fake:payload
18828     # "b9/copy-to-ecx"
18829     0xe/imm32/size
18830     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
18831 _string_ba_copy_to_edx:  # (payload array byte)
18832     0x11/imm32/alloc-id:fake:payload
18833     # "ba/copy-to-edx"
18834     0xe/imm32/size
18835     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
18836 _string_bb_copy_to_ebx:  # (payload array byte)
18837     0x11/imm32/alloc-id:fake:payload
18838     # "bb/copy-to-ebx"
18839     0xe/imm32/size
18840     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
18841 _string_be_copy_to_esi:  # (payload array byte)
18842     0x11/imm32/alloc-id:fake:payload
18843     # "be/copy-to-esi"
18844     0xe/imm32/size
18845     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
18846 _string_bf_copy_to_edi:  # (payload array byte)
18847     0x11/imm32/alloc-id:fake:payload
18848     # "bf/copy-to-edi"
18849     0xe/imm32/size
18850     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
18851 _string_c7_subop_copy:  # (payload array byte)
18852     0x11/imm32/alloc-id:fake:payload
18853     # "c7 0/subop/copy"
18854     0xf/imm32/size
18855     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
18856 _string_e9_jump_label:  # (payload array byte)
18857     0x11/imm32/alloc-id:fake:payload
18858     # "e9/jump"
18859     0x7/imm32/size
18860     0x65/e 0x39/9 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p
18861 _string_e9_jump_break:  # (payload array byte)
18862     0x11/imm32/alloc-id:fake:payload
18863     # "e9/jump break/disp32"
18864     0x14/imm32/size
18865     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
18866 _string_e9_jump_loop:  # (payload array byte)
18867     0x11/imm32/alloc-id:fake:payload
18868     # "e9/jump loop/disp32"
18869     0x13/imm32/size
18870     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
18871 _string_ff_subop_increment:  # (payload array byte)
18872     0x11/imm32/alloc-id:fake:payload
18873     # "ff 0/subop/increment"
18874     0x14/imm32/size
18875     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
18876 _string_ff_subop_decrement:  # (payload array byte)
18877     0x11/imm32/alloc-id:fake:payload
18878     # "ff 1/subop/decrement"
18879     0x14/imm32/size
18880     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
18881 _string_c1_subop_shift_left:  # (payload array byte)
18882     0x11/imm32/alloc-id:fake:payload
18883     # "c1/shift 4/subop/left"
18884     0x15/imm32/size
18885     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
18886 _string_c1_subop_shift_right_padding_zeroes:  # (payload array byte)
18887     0x11/imm32/alloc-id:fake:payload
18888     # "c1/shift 5/subop/right-padding-zeroes"
18889     0x25/imm32/size
18890     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
18891 _string_c1_subop_shift_right_preserving_sign:  # (payload array byte)
18892     0x11/imm32/alloc-id:fake:payload
18893     # "c1/shift 7/subop/right-preserving-sign"
18894     0x26/imm32/size
18895     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
18896 
18897 Single-int-var-in-mem:  # (payload list var)
18898     0x11/imm32/alloc-id:fake:payload
18899     0x11/imm32/alloc-id:fake
18900     Int-var-in-mem/imm32
18901     0/imm32/next
18902     0/imm32/next
18903 
18904 Int-var-in-mem:  # (payload 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     1/imm32/some-stack-offset
18912     0/imm32/no-register
18913     0/imm32/no-register
18914 
18915 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
18916 Single-byte-var-in-mem:  # (payload list var)
18917     0x11/imm32/alloc-id:fake:payload
18918     0x11/imm32/alloc-id:fake
18919     Byte-var-in-mem/imm32
18920     0/imm32/next
18921     0/imm32/next
18922 
18923 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
18924 Byte-var-in-mem:  # (payload var)
18925     0x11/imm32/alloc-id:fake:payload
18926     0/imm32/name
18927     0/imm32/name
18928     0x11/imm32/alloc-id:fake
18929     Type-byte/imm32
18930     1/imm32/some-block-depth
18931     1/imm32/some-stack-offset
18932     0/imm32/no-register
18933     0/imm32/no-register
18934 
18935 Two-args-int-stack-int-reg:  # (payload list var)
18936     0x11/imm32/alloc-id:fake:payload
18937     0x11/imm32/alloc-id:fake
18938     Int-var-in-mem/imm32
18939     0x11/imm32/alloc-id:fake
18940     Single-int-var-in-some-register/imm32/next
18941 
18942 Two-int-args-in-regs:  # (payload list var)
18943     0x11/imm32/alloc-id:fake:payload
18944     0x11/imm32/alloc-id:fake
18945     Int-var-in-some-register/imm32
18946     0x11/imm32/alloc-id:fake
18947     Single-int-var-in-some-register/imm32/next
18948 
18949 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
18950 Two-args-byte-stack-byte-reg:  # (payload list var)
18951     0x11/imm32/alloc-id:fake:payload
18952     0x11/imm32/alloc-id:fake
18953     Byte-var-in-mem/imm32
18954     0x11/imm32/alloc-id:fake
18955     Single-byte-var-in-some-register/imm32/next
18956 
18957 Two-args-int-reg-int-stack:  # (payload list var)
18958     0x11/imm32/alloc-id:fake:payload
18959     0x11/imm32/alloc-id:fake
18960     Int-var-in-some-register/imm32
18961     0x11/imm32/alloc-id:fake
18962     Single-int-var-in-mem/imm32/next
18963 
18964 Two-args-int-eax-int-literal:  # (payload list var)
18965     0x11/imm32/alloc-id:fake:payload
18966     0x11/imm32/alloc-id:fake
18967     Int-var-in-eax/imm32
18968     0x11/imm32/alloc-id:fake
18969     Single-lit-var/imm32/next
18970 
18971 Int-var-and-literal:  # (payload list var)
18972     0x11/imm32/alloc-id:fake:payload
18973     0x11/imm32/alloc-id:fake
18974     Int-var-in-mem/imm32
18975     0x11/imm32/alloc-id:fake
18976     Single-lit-var/imm32/next
18977 
18978 Int-var-in-register-and-literal:  # (payload list var)
18979     0x11/imm32/alloc-id:fake:payload
18980     0x11/imm32/alloc-id:fake
18981     Int-var-in-some-register/imm32
18982     0x11/imm32/alloc-id:fake
18983     Single-lit-var/imm32/next
18984 
18985 Single-int-var-in-some-register:  # (payload list var)
18986     0x11/imm32/alloc-id:fake:payload
18987     0x11/imm32/alloc-id:fake
18988     Int-var-in-some-register/imm32
18989     0/imm32/next
18990     0/imm32/next
18991 
18992 Single-addr-var-in-some-register:  # (payload list var)
18993     0x11/imm32/alloc-id:fake:payload
18994     0x11/imm32/alloc-id:fake
18995     Addr-var-in-some-register/imm32
18996     0/imm32/next
18997     0/imm32/next
18998 
18999 Single-byte-var-in-some-register:  # (payload list var)
19000     0x11/imm32/alloc-id:fake:payload
19001     0x11/imm32/alloc-id:fake
19002     Byte-var-in-some-register/imm32
19003     0/imm32/next
19004     0/imm32/next
19005 
19006 Int-var-in-some-register:  # (payload var)
19007     0x11/imm32/alloc-id:fake:payload
19008     0/imm32/name
19009     0/imm32/name
19010     0x11/imm32/alloc-id:fake
19011     Type-int/imm32
19012     1/imm32/some-block-depth
19013     0/imm32/no-stack-offset
19014     0x11/imm32/alloc-id:fake
19015     Any-register/imm32
19016 
19017 Any-register:  # (payload array byte)
19018     0x11/imm32/alloc-id:fake:payload
19019     1/imm32/size
19020     # data
19021     2a/asterisk
19022 
19023 Addr-var-in-some-register:  # (payload var)
19024     0x11/imm32/alloc-id:fake:payload
19025     0/imm32/name
19026     0/imm32/name
19027     0x11/imm32/alloc-id:fake
19028     Type-addr/imm32
19029     1/imm32/some-block-depth
19030     0/imm32/no-stack-offset
19031     0x11/imm32/alloc-id:fake
19032     Any-register/imm32
19033 
19034 Byte-var-in-some-register:  # (payload var)
19035     0x11/imm32/alloc-id:fake:payload
19036     0/imm32/name
19037     0/imm32/name
19038     0x11/imm32/alloc-id:fake
19039     Type-byte/imm32
19040     1/imm32/some-block-depth
19041     0/imm32/no-stack-offset
19042     0x11/imm32/alloc-id:fake
19043     Any-register/imm32
19044 
19045 Single-int-var-in-eax:  # (payload list var)
19046     0x11/imm32/alloc-id:fake:payload
19047     0x11/imm32/alloc-id:fake
19048     Int-var-in-eax/imm32
19049     0/imm32/next
19050     0/imm32/next
19051 
19052 Int-var-in-eax:
19053     0x11/imm32/alloc-id:fake:payload
19054     0/imm32/name
19055     0/imm32/name
19056     0x11/imm32/alloc-id:fake
19057     Type-int/imm32
19058     1/imm32/some-block-depth
19059     0/imm32/no-stack-offset
19060     0x11/imm32/alloc-id:fake
19061     $Register-eax/imm32
19062 
19063 Single-int-var-in-ecx:  # (payload list var)
19064     0x11/imm32/alloc-id:fake:payload
19065     0x11/imm32/alloc-id:fake
19066     Int-var-in-ecx/imm32
19067     0/imm32/next
19068     0/imm32/next
19069 
19070 Int-var-in-ecx:
19071     0x11/imm32/alloc-id:fake:payload
19072     0/imm32/name
19073     0/imm32/name
19074     0x11/imm32/alloc-id:fake
19075     Type-int/imm32
19076     1/imm32/some-block-depth
19077     0/imm32/no-stack-offset
19078     0x11/imm32/alloc-id:fake
19079     $Register-ecx/imm32/register
19080 
19081 Single-int-var-in-edx:  # (payload list var)
19082     0x11/imm32/alloc-id:fake:payload
19083     0x11/imm32/alloc-id:fake
19084     Int-var-in-edx/imm32
19085     0/imm32/next
19086     0/imm32/next
19087 
19088 Int-var-in-edx:  # (payload list var)
19089     0x11/imm32/alloc-id:fake:payload
19090     0/imm32/name
19091     0/imm32/name
19092     0x11/imm32/alloc-id:fake
19093     Type-int/imm32
19094     1/imm32/some-block-depth
19095     0/imm32/no-stack-offset
19096     0x11/imm32/alloc-id:fake
19097     $Register-edx/imm32/register
19098 
19099 Single-int-var-in-ebx:  # (payload list var)
19100     0x11/imm32/alloc-id:fake:payload
19101     0x11/imm32/alloc-id:fake
19102     Int-var-in-ebx/imm32
19103     0/imm32/next
19104     0/imm32/next
19105 
19106 Int-var-in-ebx:  # (payload list var)
19107     0x11/imm32/alloc-id:fake:payload
19108     0/imm32/name
19109     0/imm32/name
19110     0x11/imm32/alloc-id:fake
19111     Type-int/imm32
19112     1/imm32/some-block-depth
19113     0/imm32/no-stack-offset
19114     0x11/imm32/alloc-id:fake
19115     $Register-ebx/imm32/register
19116 
19117 Single-int-var-in-esi:  # (payload list var)
19118     0x11/imm32/alloc-id:fake:payload
19119     0x11/imm32/alloc-id:fake
19120     Int-var-in-esi/imm32
19121     0/imm32/next
19122     0/imm32/next
19123 
19124 Int-var-in-esi:  # (payload list var)
19125     0x11/imm32/alloc-id:fake:payload
19126     0/imm32/name
19127     0/imm32/name
19128     0x11/imm32/alloc-id:fake
19129     Type-int/imm32
19130     1/imm32/some-block-depth
19131     0/imm32/no-stack-offset
19132     0x11/imm32/alloc-id:fake
19133     $Register-esi/imm32/register
19134 
19135 Single-int-var-in-edi:  # (payload list var)
19136     0x11/imm32/alloc-id:fake:payload
19137     0x11/imm32/alloc-id:fake
19138     Int-var-in-edi/imm32
19139     0/imm32/next
19140     0/imm32/next
19141 
19142 Int-var-in-edi:  # (payload list var)
19143     0x11/imm32/alloc-id:fake:payload
19144     0/imm32/name
19145     0/imm32/name
19146     0x11/imm32/alloc-id:fake
19147     Type-int/imm32
19148     1/imm32/some-block-depth
19149     0/imm32/no-stack-offset
19150     0x11/imm32/alloc-id:fake
19151     $Register-edi/imm32/register
19152 
19153 Single-lit-var:  # (payload list var)
19154     0x11/imm32/alloc-id:fake:payload
19155     0x11/imm32/alloc-id:fake
19156     Lit-var/imm32
19157     0/imm32/next
19158     0/imm32/next
19159 
19160 Lit-var:  # (payload var)
19161     0x11/imm32/alloc-id:fake:payload
19162     0/imm32/name
19163     0/imm32/name
19164     0x11/imm32/alloc-id:fake
19165     Type-literal/imm32
19166     1/imm32/some-block-depth
19167     0/imm32/no-stack-offset
19168     0/imm32/no-register
19169     0/imm32/no-register
19170 
19171 Type-int:  # (payload type-tree)
19172     0x11/imm32/alloc-id:fake:payload
19173     1/imm32/is-atom
19174     1/imm32/value:int
19175     0/imm32/left:unused
19176     0/imm32/right:null
19177     0/imm32/right:null
19178 
19179 Type-literal:  # (payload type-tree)
19180     0x11/imm32/alloc-id:fake:payload
19181     1/imm32/is-atom
19182     0/imm32/value:literal
19183     0/imm32/left:unused
19184     0/imm32/right:null
19185     0/imm32/right:null
19186 
19187 Type-addr:  # (payload type-tree)
19188     0x11/imm32/alloc-id:fake:payload
19189     1/imm32/is-atom
19190     2/imm32/value:addr
19191     0/imm32/left:unused
19192     0/imm32/right:null
19193     0/imm32/right:null
19194 
19195 Type-byte:  # (payload type-tree)
19196     0x11/imm32/alloc-id:fake:payload
19197     1/imm32/is-atom
19198     8/imm32/value:byte
19199     0/imm32/left:unused
19200     0/imm32/right:null
19201     0/imm32/right:null
19202 
19203 == code
19204 emit-subx-primitive:  # out: (addr buffered-file), stmt: (addr stmt), primitive: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
19205     # . prologue
19206     55/push-ebp
19207     89/<- %ebp 4/r32/esp
19208     # . save registers
19209     50/push-eax
19210     51/push-ecx
19211     # ecx = primitive
19212     8b/-> *(ebp+0x10) 1/r32/ecx
19213     # emit primitive name
19214     (emit-indent *(ebp+8) *Curr-block-depth)
19215     (lookup *(ecx+0x18) *(ecx+0x1c))  # Primitive-subx-name Primitive-subx-name => eax
19216     (write-buffered *(ebp+8) %eax)
19217     # emit rm32 if necessary
19218     (emit-subx-rm32 *(ebp+8) *(ecx+0x20) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-rm32
19219     # emit r32 if necessary
19220     (emit-subx-r32 *(ebp+8) *(ecx+0x24) *(ebp+0xc))  # Primitive-subx-r32
19221     # emit imm32 if necessary
19222     (emit-subx-imm32 *(ebp+8) *(ecx+0x28) *(ebp+0xc))  # Primitive-subx-imm32
19223     # emit imm8 if necessary
19224     (emit-subx-imm8 *(ebp+8) *(ecx+0x2c) *(ebp+0xc))  # Primitive-subx-imm8
19225     # emit disp32 if necessary
19226     (emit-subx-disp32 *(ebp+8) *(ecx+0x30) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-disp32
19227     (write-buffered *(ebp+8) Newline)
19228 $emit-subx-primitive:end:
19229     # . restore registers
19230     59/pop-to-ecx
19231     58/pop-to-eax
19232     # . epilogue
19233     89/<- %esp 5/r32/ebp
19234     5d/pop-to-ebp
19235     c3/return
19236 
19237 emit-subx-rm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
19238     # . prologue
19239     55/push-ebp
19240     89/<- %ebp 4/r32/esp
19241     # . save registers
19242     50/push-eax
19243     # if (l == 0) return
19244     81 7/subop/compare *(ebp+0xc) 0/imm32
19245     74/jump-if-= $emit-subx-rm32:end/disp8
19246     # var v/eax: (addr stmt-var)
19247     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
19248     (emit-subx-var-as-rm32 *(ebp+8) %eax)
19249 $emit-subx-rm32:end:
19250     # . restore registers
19251     58/pop-to-eax
19252     # . epilogue
19253     89/<- %esp 5/r32/ebp
19254     5d/pop-to-ebp
19255     c3/return
19256 
19257 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)
19258     # . prologue
19259     55/push-ebp
19260     89/<- %ebp 4/r32/esp
19261     # . save registers
19262     51/push-ecx
19263     # eax = l
19264     8b/-> *(ebp+0xc) 0/r32/eax
19265     # ecx = stmt
19266     8b/-> *(ebp+8) 1/r32/ecx
19267     # if (l == 1) return stmt->inouts
19268     {
19269       3d/compare-eax-and 1/imm32
19270       75/jump-if-!= break/disp8
19271 $get-stmt-operand-from-arg-location:1:
19272       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
19273       eb/jump $get-stmt-operand-from-arg-location:end/disp8
19274     }
19275     # if (l == 2) return stmt->inouts->next
19276     {
19277       3d/compare-eax-and 2/imm32
19278       75/jump-if-!= break/disp8
19279 $get-stmt-operand-from-arg-location:2:
19280       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
19281       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
19282       eb/jump $get-stmt-operand-from-arg-location:end/disp8
19283     }
19284     # if (l == 3) return stmt->outputs
19285     {
19286       3d/compare-eax-and 3/imm32
19287       75/jump-if-!= break/disp8
19288 $get-stmt-operand-from-arg-location:3:
19289       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
19290       eb/jump $get-stmt-operand-from-arg-location:end/disp8
19291     }
19292     # abort
19293     e9/jump $get-stmt-operand-from-arg-location:abort/disp32
19294 $get-stmt-operand-from-arg-location:end:
19295     # . restore registers
19296     59/pop-to-ecx
19297     # . epilogue
19298     89/<- %esp 5/r32/ebp
19299     5d/pop-to-ebp
19300     c3/return
19301 
19302 $get-stmt-operand-from-arg-location:abort:
19303     # error("invalid arg-location " eax)
19304     (write-buffered *(ebp+0x10) "invalid arg-location ")
19305     (write-int32-hex-buffered *(ebp+0x10) %eax)
19306     (write-buffered *(ebp+0x10) Newline)
19307     (flush *(ebp+0x10))
19308     (stop *(ebp+0x14) 1)
19309     # never gets here
19310 
19311 emit-subx-r32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
19312     # . prologue
19313     55/push-ebp
19314     89/<- %ebp 4/r32/esp
19315     # . save registers
19316     50/push-eax
19317     51/push-ecx
19318     # if (l == 0) return
19319     81 7/subop/compare *(ebp+0xc) 0/imm32
19320     0f 84/jump-if-= $emit-subx-r32:end/disp32
19321     # var v/eax: (addr stmt-var)
19322     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
19323     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
19324     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
19325     (maybe-get Mu-registers %eax 0xc)  # => eax: (addr register-index)
19326     (write-buffered *(ebp+8) Space)
19327     (write-int32-hex-buffered *(ebp+8) *eax)
19328     (write-buffered *(ebp+8) "/r32")
19329 $emit-subx-r32:end:
19330     # . restore registers
19331     59/pop-to-ecx
19332     58/pop-to-eax
19333     # . epilogue
19334     89/<- %esp 5/r32/ebp
19335     5d/pop-to-ebp
19336     c3/return
19337 
19338 emit-subx-imm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
19339     # . prologue
19340     55/push-ebp
19341     89/<- %ebp 4/r32/esp
19342     # . save registers
19343     50/push-eax
19344     51/push-ecx
19345     # if (l == 0) return
19346     81 7/subop/compare *(ebp+0xc) 0/imm32
19347     0f 84/jump-if-= $emit-subx-imm32:end/disp32
19348     # var v/eax: (handle var)
19349     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
19350     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
19351     (lookup *eax *(eax+4))  # Var-name Var-name => eax
19352     (write-buffered *(ebp+8) Space)
19353     (write-buffered *(ebp+8) %eax)
19354     (write-buffered *(ebp+8) "/imm32")
19355 $emit-subx-imm32:end:
19356     # . restore registers
19357     59/pop-to-ecx
19358     58/pop-to-eax
19359     # . epilogue
19360     89/<- %esp 5/r32/ebp
19361     5d/pop-to-ebp
19362     c3/return
19363 
19364 emit-subx-imm8:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
19365     # . prologue
19366     55/push-ebp
19367     89/<- %ebp 4/r32/esp
19368     # . save registers
19369     50/push-eax
19370     51/push-ecx
19371     # if (l == 0) return
19372     81 7/subop/compare *(ebp+0xc) 0/imm32
19373     0f 84/jump-if-= $emit-subx-imm32:end/disp32
19374     # var v/eax: (handle var)
19375     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
19376     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
19377     (lookup *eax *(eax+4))  # Var-name Var-name => eax
19378     (write-buffered *(ebp+8) Space)
19379     (write-buffered *(ebp+8) %eax)
19380     (write-buffered *(ebp+8) "/imm8")
19381 $emit-subx-imm8:end:
19382     # . restore registers
19383     59/pop-to-ecx
19384     58/pop-to-eax
19385     # . epilogue
19386     89/<- %esp 5/r32/ebp
19387     5d/pop-to-ebp
19388     c3/return
19389 
19390 emit-subx-disp32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
19391     # . prologue
19392     55/push-ebp
19393     89/<- %ebp 4/r32/esp
19394     # . save registers
19395     50/push-eax
19396     51/push-ecx
19397     # if (location == 0) return
19398     81 7/subop/compare *(ebp+0xc) 0/imm32
19399     0f 84/jump-if-= $emit-subx-disp32:end/disp32
19400     # var v/eax: (addr stmt-var)
19401     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
19402     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
19403     (lookup *eax *(eax+4))  # Var-name Var-name => eax
19404     (write-buffered *(ebp+8) Space)
19405     (write-buffered *(ebp+8) %eax)
19406     # hack: if instruction operation starts with "break", emit ":break"
19407     # var name/ecx: (addr array byte) = lookup(stmt->operation)
19408     8b/-> *(ebp+0x10) 0/r32/eax
19409     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
19410     89/<- %ecx 0/r32/eax
19411     {
19412       (string-starts-with? %ecx "break")  # => eax
19413       3d/compare-eax-and 0/imm32/false
19414       74/jump-if-= break/disp8
19415       (write-buffered *(ebp+8) ":break")
19416     }
19417     # hack: if instruction operation starts with "loop", emit ":loop"
19418     {
19419       (string-starts-with? %ecx "loop")  # => eax
19420       3d/compare-eax-and 0/imm32/false
19421       74/jump-if-= break/disp8
19422       (write-buffered *(ebp+8) ":loop")
19423     }
19424     (write-buffered *(ebp+8) "/disp32")
19425 $emit-subx-disp32:end:
19426     # . restore registers
19427     59/pop-to-ecx
19428     58/pop-to-eax
19429     # . epilogue
19430     89/<- %esp 5/r32/ebp
19431     5d/pop-to-ebp
19432     c3/return
19433 
19434 emit-call:  # out: (addr buffered-file), stmt: (addr stmt)
19435     # . prologue
19436     55/push-ebp
19437     89/<- %ebp 4/r32/esp
19438     # . save registers
19439     50/push-eax
19440     51/push-ecx
19441     #
19442     (emit-indent *(ebp+8) *Curr-block-depth)
19443     (write-buffered *(ebp+8) "(")
19444     # ecx = stmt
19445     8b/-> *(ebp+0xc) 1/r32/ecx
19446     # - emit function name
19447     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
19448     (write-buffered *(ebp+8) %eax)
19449     # - emit arguments
19450     # var curr/eax: (addr stmt-var) = lookup(stmt->inouts)
19451     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
19452     {
19453       # if (curr == null) break
19454       3d/compare-eax-and 0/imm32
19455       74/jump-if-= break/disp8
19456       #
19457       (emit-subx-call-operand *(ebp+8) %eax)
19458       # curr = lookup(curr->next)
19459       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
19460       eb/jump loop/disp8
19461     }
19462     #
19463     (write-buffered *(ebp+8) ")\n")
19464 $emit-call:end:
19465     # . restore registers
19466     59/pop-to-ecx
19467     58/pop-to-eax
19468     # . epilogue
19469     89/<- %esp 5/r32/ebp
19470     5d/pop-to-ebp
19471     c3/return
19472 
19473 emit-subx-call-operand:  # out: (addr buffered-file), s: (addr stmt-var)
19474     # shares code with emit-subx-var-as-rm32
19475     # . prologue
19476     55/push-ebp
19477     89/<- %ebp 4/r32/esp
19478     # . save registers
19479     50/push-eax
19480     51/push-ecx
19481     56/push-esi
19482     # ecx = s
19483     8b/-> *(ebp+0xc) 1/r32/ecx
19484     # var operand/esi: (addr var) = lookup(s->value)
19485     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
19486     89/<- %esi 0/r32/eax
19487     # if (operand->register && !s->is-deref?) emit "%__"
19488     {
19489 $emit-subx-call-operand:check-for-register-direct:
19490       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
19491       74/jump-if-= break/disp8
19492       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
19493       75/jump-if-!= break/disp8
19494 $emit-subx-call-operand:register-direct:
19495       (write-buffered *(ebp+8) " %")
19496       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
19497       (write-buffered *(ebp+8) %eax)
19498       e9/jump $emit-subx-call-operand:end/disp32
19499     }
19500     # else if (operand->register && s->is-deref?) emit "*__"
19501     {
19502 $emit-subx-call-operand:check-for-register-indirect:
19503       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
19504       74/jump-if-= break/disp8
19505       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
19506       74/jump-if-= break/disp8
19507 $emit-subx-call-operand:register-indirect:
19508       (emit-subx-call-operand-register-indirect *(ebp+8) %esi)
19509       e9/jump $emit-subx-call-operand:end/disp32
19510     }
19511     # else if (operand->stack-offset) emit "*(ebp+__)"
19512     {
19513       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
19514       74/jump-if-= break/disp8
19515 $emit-subx-call-operand:stack:
19516       (emit-subx-call-operand-stack *(ebp+8) %esi)
19517       e9/jump $emit-subx-call-operand:end/disp32
19518     }
19519     # else if (operand->type == literal) emit "__"
19520     {
19521       (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
19522       81 7/subop/compare *(eax+4) 0/imm32  # Type-tree-left
19523       75/jump-if-!= break/disp8
19524 $emit-subx-call-operand:literal:
19525       (write-buffered *(ebp+8) Space)
19526       (lookup *esi *(esi+4))  # Var-name Var-name => eax
19527       (write-buffered *(ebp+8) %eax)
19528     }
19529 $emit-subx-call-operand:end:
19530     # . restore registers
19531     5e/pop-to-esi
19532     59/pop-to-ecx
19533     58/pop-to-eax
19534     # . epilogue
19535     89/<- %esp 5/r32/ebp
19536     5d/pop-to-ebp
19537     c3/return
19538 
19539 emit-subx-call-operand-register-indirect:  # out: (addr buffered-file), v: (addr var)
19540     # . prologue
19541     55/push-ebp
19542     89/<- %ebp 4/r32/esp
19543     # . save registers
19544     50/push-eax
19545     51/push-ecx
19546     56/push-esi
19547     # esi = v
19548     8b/-> *(ebp+0xc) 6/r32/esi
19549     # var size/ecx: int = size-of-deref(v)
19550     (size-of-deref %esi)  # => eax
19551     89/<- %ecx 0/r32/eax
19552     # var reg-name/esi: (addr array byte) = lookup(v->register)
19553     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
19554     89/<- %esi 0/r32/eax
19555     # TODO: assert size is a multiple of 4
19556     # var i/eax: int = 0
19557     b8/copy-to-eax 0/imm32
19558     {
19559 $emit-subx-call-operand-register-indirect:loop:
19560       # if (i >= size) break
19561       39/compare %eax 1/r32/ecx
19562       7d/jump-if->= break/disp8
19563       # emit " *(" v->register "+" i ")"
19564       (write-buffered *(ebp+8) " *(")
19565       (write-buffered *(ebp+8) %esi)
19566       (write-buffered *(ebp+8) "+")
19567       (write-int32-hex-buffered *(ebp+8) %eax)
19568       (write-buffered *(ebp+8) ")")
19569       # i += 4
19570       05/add-to-eax 4/imm32
19571       #
19572       eb/jump loop/disp8
19573     }
19574 $emit-subx-call-operand-register-indirect:end:
19575     # . restore registers
19576     5e/pop-to-esi
19577     59/pop-to-ecx
19578     58/pop-to-eax
19579     # . epilogue
19580     89/<- %esp 5/r32/ebp
19581     5d/pop-to-ebp
19582     c3/return
19583 
19584 emit-subx-call-operand-stack:  # out: (addr buffered-file), v: (addr var)
19585     # . prologue
19586     55/push-ebp
19587     89/<- %ebp 4/r32/esp
19588     # . save registers
19589     50/push-eax
19590     51/push-ecx
19591     56/push-esi
19592     # esi = v
19593     8b/-> *(ebp+0xc) 6/r32/esi
19594     # var curr/ecx: int = v->offset
19595     8b/-> *(esi+0x14) 1/r32/ecx  # Var-offset
19596     # var max/eax: int = v->offset + size-of(v)
19597     (size-of %esi)  # => eax
19598     # TODO: assert size is a multiple of 4
19599     01/add-to %eax 1/r32/ecx
19600     {
19601 $emit-subx-call-operand-stack:loop:
19602       # if (curr >= max) break
19603       39/compare %ecx 0/r32/eax
19604       7d/jump-if->= break/disp8
19605       # emit " *(ebp+" curr ")"
19606       (write-buffered *(ebp+8) " *(ebp+")
19607       (write-int32-hex-buffered *(ebp+8) %ecx)
19608       (write-buffered *(ebp+8) ")")
19609       # i += 4
19610       81 0/subop/add %ecx 4/imm32
19611       #
19612       eb/jump loop/disp8
19613     }
19614 $emit-subx-call-operand-stack:end:
19615     # . restore registers
19616     5e/pop-to-esi
19617     59/pop-to-ecx
19618     58/pop-to-eax
19619     # . epilogue
19620     89/<- %esp 5/r32/ebp
19621     5d/pop-to-ebp
19622     c3/return
19623 
19624 emit-subx-var-as-rm32:  # out: (addr buffered-file), s: (addr stmt-var)
19625     # . prologue
19626     55/push-ebp
19627     89/<- %ebp 4/r32/esp
19628     # . save registers
19629     50/push-eax
19630     51/push-ecx
19631     56/push-esi
19632     # ecx = s
19633     8b/-> *(ebp+0xc) 1/r32/ecx
19634     # var operand/esi: (addr var) = lookup(s->value)
19635     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
19636     89/<- %esi 0/r32/eax
19637     # if (operand->register && s->is-deref?) emit "*__"
19638     {
19639 $emit-subx-var-as-rm32:check-for-register-indirect:
19640       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
19641       74/jump-if-= break/disp8
19642       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
19643       74/jump-if-= break/disp8
19644 $emit-subx-var-as-rm32:register-indirect:
19645       (write-buffered *(ebp+8) " *")
19646       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
19647       (write-buffered *(ebp+8) %eax)
19648       e9/jump $emit-subx-var-as-rm32:end/disp32
19649     }
19650     # if (operand->register && !s->is-deref?) emit "%__"
19651     {
19652 $emit-subx-var-as-rm32:check-for-register-direct:
19653       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
19654       74/jump-if-= break/disp8
19655       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
19656       75/jump-if-!= break/disp8
19657 $emit-subx-var-as-rm32:register-direct:
19658       (write-buffered *(ebp+8) " %")
19659       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
19660       (write-buffered *(ebp+8) %eax)
19661       e9/jump $emit-subx-var-as-rm32:end/disp32
19662     }
19663     # else if (operand->stack-offset) emit "*(ebp+__)"
19664     {
19665       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
19666       74/jump-if-= break/disp8
19667 $emit-subx-var-as-rm32:stack:
19668       (write-buffered *(ebp+8) Space)
19669       (write-buffered *(ebp+8) "*(ebp+")
19670       (write-int32-hex-buffered *(ebp+8) *(esi+0x14))  # Var-offset
19671       (write-buffered *(ebp+8) ")")
19672     }
19673 $emit-subx-var-as-rm32:end:
19674     # . restore registers
19675     5e/pop-to-esi
19676     59/pop-to-ecx
19677     58/pop-to-eax
19678     # . epilogue
19679     89/<- %esp 5/r32/ebp
19680     5d/pop-to-ebp
19681     c3/return
19682 
19683 find-matching-primitive:  # primitives: (addr primitive), stmt: (addr stmt) -> result/eax: (addr primitive)
19684     # . prologue
19685     55/push-ebp
19686     89/<- %ebp 4/r32/esp
19687     # . save registers
19688     51/push-ecx
19689     # var curr/ecx: (addr primitive) = primitives
19690     8b/-> *(ebp+8) 1/r32/ecx
19691     {
19692 $find-matching-primitive:loop:
19693       # if (curr == null) break
19694       81 7/subop/compare %ecx 0/imm32
19695       74/jump-if-= break/disp8
19696       # if match(curr, stmt) return curr
19697       {
19698         (mu-stmt-matches-primitive? *(ebp+0xc) %ecx)  # => eax
19699         3d/compare-eax-and 0/imm32/false
19700         74/jump-if-= break/disp8
19701         89/<- %eax 1/r32/ecx
19702         eb/jump $find-matching-primitive:end/disp8
19703       }
19704 $find-matching-primitive:next-primitive:
19705       # curr = curr->next
19706       (lookup *(ecx+0x38) *(ecx+0x3c))  # Primitive-next Primitive-next => eax
19707       89/<- %ecx 0/r32/eax
19708       #
19709       e9/jump loop/disp32
19710     }
19711     # return null
19712     b8/copy-to-eax 0/imm32
19713 $find-matching-primitive:end:
19714     # . restore registers
19715     59/pop-to-ecx
19716     # . epilogue
19717     89/<- %esp 5/r32/ebp
19718     5d/pop-to-ebp
19719     c3/return
19720 
19721 mu-stmt-matches-primitive?:  # stmt: (addr stmt), primitive: (addr primitive) -> result/eax: boolean
19722     # A mu stmt matches a primitive if the name matches, all the inout vars
19723     # match, and all the output vars match.
19724     # Vars match if types match and registers match.
19725     # In addition, a stmt output matches a primitive's output if types match
19726     # and the primitive has a wildcard register.
19727     # . prologue
19728     55/push-ebp
19729     89/<- %ebp 4/r32/esp
19730     # . save registers
19731     51/push-ecx
19732     52/push-edx
19733     53/push-ebx
19734     56/push-esi
19735     57/push-edi
19736     # ecx = stmt
19737     8b/-> *(ebp+8) 1/r32/ecx
19738     # edx = primitive
19739     8b/-> *(ebp+0xc) 2/r32/edx
19740     {
19741 $mu-stmt-matches-primitive?:check-name:
19742       # if (primitive->name != stmt->operation) return false
19743       # . var esi: (addr array byte) = lookup(stmt->operation)
19744       (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
19745       89/<- %esi 0/r32/eax
19746       # . var edi: (addr array byte) = lookup(primitive->name)
19747       (lookup *edx *(edx+4))  # Primitive-name Primitive-name => eax
19748       89/<- %edi 0/r32/eax
19749       (string-equal? %esi %edi)  # => eax
19750       3d/compare-eax-and 0/imm32/false
19751       75/jump-if-!= break/disp8
19752       b8/copy-to-eax 0/imm32
19753       e9/jump $mu-stmt-matches-primitive?:end/disp32
19754     }
19755     # var curr/esi: (addr stmt-var) = lookup(stmt->inouts)
19756     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
19757     89/<- %esi 0/r32/eax
19758     # var curr2/edi: (addr list var) = lookup(primitive->inouts)
19759     (lookup *(edx+8) *(edx+0xc))  # Primitive-inouts Primitive-inouts => eax
19760     89/<- %edi 0/r32/eax
19761     {
19762 $mu-stmt-matches-primitive?:inouts-loop:
19763       # if (curr == 0 && curr2 == 0) move on to check outputs
19764       {
19765 $mu-stmt-matches-primitive?:check-both-inouts-null:
19766         81 7/subop/compare %esi 0/imm32
19767         75/jump-if-!= break/disp8
19768 $mu-stmt-matches-primitive?:stmt-inout-null:
19769         81 7/subop/compare %edi 0/imm32
19770         0f 84/jump-if-= $mu-stmt-matches-primitive?:check-outputs/disp32
19771 $mu-stmt-matches-primitive?:stmt-inout-null-and-prim-inout-not-null:
19772         # return false
19773         b8/copy-to-eax 0/imm32/false
19774         e9/jump $mu-stmt-matches-primitive?:end/disp32
19775       }
19776       # if (curr2 == 0) return false
19777       {
19778 $mu-stmt-matches-primitive?:check-prim-inout-null:
19779         81 7/subop/compare %edi 0/imm32
19780         75/jump-if-!= break/disp8
19781 $mu-stmt-matches-primitive?:prim-inout-null:
19782         b8/copy-to-eax 0/imm32/false
19783         e9/jump $mu-stmt-matches-primitive?:end/disp32
19784       }
19785       # if (curr != curr2) return false
19786       {
19787 $mu-stmt-matches-primitive?:check-inouts-match:
19788         (lookup *edi *(edi+4))  # List-value List-value => eax
19789         (operand-matches-primitive? %esi %eax)  # => eax
19790         3d/compare-eax-and 0/imm32/false
19791         75/jump-if-!= break/disp8
19792 $mu-stmt-matches-primitive?:inouts-match:
19793         b8/copy-to-eax 0/imm32/false
19794         e9/jump $mu-stmt-matches-primitive?:end/disp32
19795       }
19796 $mu-stmt-matches-primitive?:next-inout:
19797       # curr = lookup(curr->next)
19798       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
19799       89/<- %esi 0/r32/eax
19800       # curr2 = lookup(curr2->next)
19801       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
19802       89/<- %edi 0/r32/eax
19803       #
19804       e9/jump loop/disp32
19805     }
19806 $mu-stmt-matches-primitive?:check-outputs:
19807     # var curr/esi: (addr stmt-var) = lookup(stmt->outputs)
19808     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
19809     89/<- %esi 0/r32/eax
19810     # var curr2/edi: (addr list var) = lookup(primitive->outputs)
19811     (lookup *(edx+0x10) *(edx+0x14))  # Primitive-outputs Primitive-outputs => eax
19812     89/<- %edi 0/r32/eax
19813     {
19814 $mu-stmt-matches-primitive?:outputs-loop:
19815       # if (curr == 0) return (curr2 == 0)
19816       {
19817 $mu-stmt-matches-primitive?:check-both-outputs-null:
19818         81 7/subop/compare %esi 0/imm32
19819         75/jump-if-!= break/disp8
19820         {
19821 $mu-stmt-matches-primitive?:stmt-output-null:
19822           81 7/subop/compare %edi 0/imm32
19823           75/jump-if-!= break/disp8
19824 $mu-stmt-matches-primitive?:both-outputs-null:
19825           # return true
19826           b8/copy-to-eax 1/imm32
19827           e9/jump $mu-stmt-matches-primitive?:end/disp32
19828         }
19829 $mu-stmt-matches-primitive?:stmt-output-null-and-prim-output-not-null:
19830         # return false
19831         b8/copy-to-eax 0/imm32
19832         e9/jump $mu-stmt-matches-primitive?:end/disp32
19833       }
19834       # if (curr2 == 0) return false
19835       {
19836 $mu-stmt-matches-primitive?:check-prim-output-null:
19837         81 7/subop/compare %edi 0/imm32
19838         75/jump-if-!= break/disp8
19839 $mu-stmt-matches-primitive?:prim-output-is-null:
19840         b8/copy-to-eax 0/imm32
19841         e9/jump $mu-stmt-matches-primitive?:end/disp32
19842       }
19843       # if (curr != curr2) return false
19844       {
19845 $mu-stmt-matches-primitive?:check-outputs-match:
19846         (lookup *edi *(edi+4))  # List-value List-value => eax
19847         (operand-matches-primitive? %esi %eax)  # => eax
19848         3d/compare-eax-and 0/imm32/false
19849         75/jump-if-!= break/disp8
19850 $mu-stmt-matches-primitive?:outputs-match:
19851         b8/copy-to-eax 0/imm32
19852         e9/jump $mu-stmt-matches-primitive?:end/disp32
19853       }
19854 $mu-stmt-matches-primitive?:next-output:
19855       # curr = lookup(curr->next)
19856       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
19857       89/<- %esi 0/r32/eax
19858       # curr2 = lookup(curr2->next)
19859       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
19860       89/<- %edi 0/r32/eax
19861       #
19862       e9/jump loop/disp32
19863     }
19864 $mu-stmt-matches-primitive?:return-true:
19865     b8/copy-to-eax 1/imm32
19866 $mu-stmt-matches-primitive?:end:
19867     # . restore registers
19868     5f/pop-to-edi
19869     5e/pop-to-esi
19870     5b/pop-to-ebx
19871     5a/pop-to-edx
19872     59/pop-to-ecx
19873     # . epilogue
19874     89/<- %esp 5/r32/ebp
19875     5d/pop-to-ebp
19876     c3/return
19877 
19878 operand-matches-primitive?:  # s: (addr stmt-var), prim-var: (addr var) -> result/eax: boolean
19879     # . prologue
19880     55/push-ebp
19881     89/<- %ebp 4/r32/esp
19882     # . save registers
19883     51/push-ecx
19884     52/push-edx
19885     53/push-ebx
19886     56/push-esi
19887     57/push-edi
19888     # ecx = s
19889     8b/-> *(ebp+8) 1/r32/ecx
19890     # var var/esi: (addr var) = lookup(s->value)
19891     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
19892     89/<- %esi 0/r32/eax
19893     # edi = prim-var
19894     8b/-> *(ebp+0xc) 7/r32/edi
19895 $operand-matches-primitive?:check-type:
19896     # if !category-match?(var->type, prim-var->type) return false
19897     # . var vtype/ebx: (addr type-tree) = lookup(var->type)
19898     (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
19899     89/<- %ebx 0/r32/eax
19900     # . var ptype/eax: (addr type-tree) = lookup(prim-var->type)
19901     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
19902     (subx-type-category-match? %ebx %eax)  # => eax
19903     3d/compare-eax-and 0/imm32/false
19904     0f 84/jump-if-= $operand-matches-primitive?:return-false/disp32
19905     {
19906 $operand-matches-primitive?:check-register:
19907       # if prim-var is in memory and var is in register but dereference, match
19908       {
19909         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
19910         0f 85/jump-if-!= break/disp32
19911         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
19912         74/jump-if-= break/disp8
19913         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
19914         74/jump-if-= break/disp8
19915 $operand-matches-primitive?:var-deref-match:
19916         e9/jump $operand-matches-primitive?:return-true/disp32
19917       }
19918       # if prim-var is in register and var is in register but dereference, no match
19919       {
19920         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
19921         0f 84/jump-if-= break/disp32
19922         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
19923         0f 84/jump-if-= break/disp32
19924         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
19925         74/jump-if-= break/disp8
19926 $operand-matches-primitive?:var-deref-no-match:
19927         e9/jump $operand-matches-primitive?:return-false/disp32
19928       }
19929       # return false if var->register doesn't match prim-var->register
19930       {
19931         # if register addresses are equal, it's a match
19932         # var vreg/ebx: (addr array byte) = lookup(var->register)
19933         (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
19934         89/<- %ebx 0/r32/eax
19935         # var preg/ecx: (addr array byte) = lookup(prim-var->register)
19936         (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
19937         89/<- %ecx 0/r32/eax
19938         # if (vreg == preg) break
19939         39/compare %ecx 3/r32/ebx
19940         74/jump-if-= break/disp8
19941 $operand-matches-primitive?:var-register-no-match:
19942         # if either address is 0, return false
19943         81 7/subop/compare %ebx 0/imm32
19944         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
19945         81 7/subop/compare %ecx 0/imm32
19946         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
19947         # if prim-var->register is wildcard, it's a match
19948         (string-equal? %ecx "*")  # Any-register => eax
19949         3d/compare-eax-and 0/imm32/false
19950         75/jump-if-!= break/disp8
19951 $operand-matches-primitive?:wildcard-no-match:
19952         # if string contents aren't equal, return false
19953         (string-equal? %ecx %ebx)  # => eax
19954         3d/compare-eax-and 0/imm32/false
19955         74/jump-if-= $operand-matches-primitive?:return-false/disp8
19956       }
19957     }
19958 $operand-matches-primitive?:return-true:
19959     b8/copy-to-eax 1/imm32/true
19960     eb/jump $operand-matches-primitive?:end/disp8
19961 $operand-matches-primitive?:return-false:
19962     b8/copy-to-eax 0/imm32/false
19963 $operand-matches-primitive?:end:
19964     # . restore registers
19965     5f/pop-to-edi
19966     5e/pop-to-esi
19967     5b/pop-to-ebx
19968     5a/pop-to-edx
19969     59/pop-to-ecx
19970     # . epilogue
19971     89/<- %esp 5/r32/ebp
19972     5d/pop-to-ebp
19973     c3/return
19974 
19975 find-matching-function:  # functions: (addr function), stmt: (addr stmt) -> result/eax: (addr function)
19976     # . prologue
19977     55/push-ebp
19978     89/<- %ebp 4/r32/esp
19979     # . save registers
19980     51/push-ecx
19981     # var curr/ecx: (handle function) = functions
19982     8b/-> *(ebp+8) 1/r32/ecx
19983     {
19984       # if (curr == null) break
19985       81 7/subop/compare %ecx 0/imm32
19986       74/jump-if-= break/disp8
19987 #?       (write-buffered Stderr "iter\n")
19988 #?       (flush Stderr)
19989       # if match(stmt, curr) return curr
19990       {
19991         (mu-stmt-matches-function? *(ebp+0xc) %ecx)  # => eax
19992         3d/compare-eax-and 0/imm32/false
19993         74/jump-if-= break/disp8
19994         89/<- %eax 1/r32/ecx
19995         eb/jump $find-matching-function:end/disp8
19996       }
19997       # curr = curr->next
19998       (lookup *(ecx+0x20) *(ecx+0x24))  # Function-next Function-next => eax
19999       89/<- %ecx 0/r32/eax
20000       #
20001       eb/jump loop/disp8
20002     }
20003     # return null
20004     b8/copy-to-eax 0/imm32
20005 $find-matching-function:end:
20006     # . restore registers
20007     59/pop-to-ecx
20008     # . epilogue
20009     89/<- %esp 5/r32/ebp
20010     5d/pop-to-ebp
20011     c3/return
20012 
20013 # Just compare names; user-defined functions don't support overloading yet.
20014 mu-stmt-matches-function?:  # stmt: (addr stmt1), function: (addr function) -> result/eax: boolean
20015     # . prologue
20016     55/push-ebp
20017     89/<- %ebp 4/r32/esp
20018     # . save registers
20019     51/push-ecx
20020     # return function->name == stmt->operation
20021     # ecx = lookup(stmt->operation)
20022     8b/-> *(ebp+8) 0/r32/eax
20023     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
20024     89/<- %ecx 0/r32/eax
20025     # eax = lookup(function->name)
20026     8b/-> *(ebp+0xc) 0/r32/eax
20027     (lookup *eax *(eax+4))  # Function-name Function-name => eax
20028     (string-equal? %eax %ecx)  # => eax
20029 $mu-stmt-matches-function?:end:
20030     # . restore registers
20031     59/pop-to-ecx
20032     # . epilogue
20033     89/<- %esp 5/r32/ebp
20034     5d/pop-to-ebp
20035     c3/return
20036 
20037 # Type-checking happens elsewhere. This method is for selecting between
20038 # primitives.
20039 subx-type-category-match?:  # a: (addr type-tree), b: (addr type-tree) -> result/eax: boolean
20040     # . prologue
20041     55/push-ebp
20042     89/<- %ebp 4/r32/esp
20043     # . save registers
20044     51/push-ecx
20045     # var alit/ecx: boolean = is-literal-type?(a)
20046     (is-simple-mu-type? *(ebp+8) 0)  # => eax
20047     89/<- %ecx 0/r32/eax
20048     # var blit/eax: boolean = is-literal-type?(b)
20049     (is-simple-mu-type? *(ebp+0xc) 0)  # => eax
20050     # return alit == blit
20051     39/compare %eax 1/r32/ecx
20052     0f 94/set-byte-if-= %al
20053     81 4/subop/and %eax 0xff/imm32
20054 $subx-type-category-match?:end:
20055     # . restore registers
20056     59/pop-to-ecx
20057     # . epilogue
20058     89/<- %esp 5/r32/ebp
20059     5d/pop-to-ebp
20060     c3/return
20061 
20062 is-simple-mu-type?:  # a: (addr type-tree), n: type-id -> result/eax: boolean
20063     # . prologue
20064     55/push-ebp
20065     89/<- %ebp 4/r32/esp
20066     # . save registers
20067     51/push-ecx
20068     # ecx = n
20069     8b/-> *(ebp+0xc) 1/r32/ecx
20070     # return (a->value == n)
20071     8b/-> *(ebp+8) 0/r32/eax
20072     39/compare *(eax+4) 1/r32/ecx  # Type-tree-value
20073     0f 94/set-byte-if-= %al
20074     81 4/subop/and %eax 0xff/imm32
20075 $is-simple-mu-type?:end:
20076     # . restore registers
20077     59/pop-to-ecx
20078     # . epilogue
20079     89/<- %esp 5/r32/ebp
20080     5d/pop-to-ebp
20081     c3/return
20082 
20083 is-mu-addr-type?:  # a: (addr type-tree) -> result/eax: boolean
20084     # . prologue
20085     55/push-ebp
20086     89/<- %ebp 4/r32/esp
20087     # eax = a
20088     8b/-> *(ebp+8) 0/r32/eax
20089     # if (!a->is-atom?) a = a->left
20090     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
20091     {
20092       75/jump-if-!= break/disp8
20093       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
20094     }
20095     # return (a->value == addr)
20096     81 7/subop/compare *(eax+4) 2/imm32/addr  # Type-tree-value
20097     0f 94/set-byte-if-= %al
20098     81 4/subop/and %eax 0xff/imm32
20099 $is-mu-addr-type?:end:
20100     # . epilogue
20101     89/<- %esp 5/r32/ebp
20102     5d/pop-to-ebp
20103     c3/return
20104 
20105 is-mu-array-type?:  # a: (addr type-tree) -> result/eax: boolean
20106     # . prologue
20107     55/push-ebp
20108     89/<- %ebp 4/r32/esp
20109     # eax = a
20110     8b/-> *(ebp+8) 0/r32/eax
20111     # if (!a->is-atom?) a = a->left
20112     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
20113     {
20114       75/jump-if-!= break/disp8
20115       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
20116     }
20117     # return (a->value == array)
20118     81 7/subop/compare *(eax+4) 3/imm32/array  # Type-tree-value
20119     0f 94/set-byte-if-= %al
20120     81 4/subop/and %eax 0xff/imm32
20121 $is-mu-array-type?:end:
20122     # . epilogue
20123     89/<- %esp 5/r32/ebp
20124     5d/pop-to-ebp
20125     c3/return
20126 
20127 is-mu-stream-type?:  # a: (addr type-tree) -> result/eax: boolean
20128     # . prologue
20129     55/push-ebp
20130     89/<- %ebp 4/r32/esp
20131     # eax = a
20132     8b/-> *(ebp+8) 0/r32/eax
20133     # if (!a->is-atom?) a = a->left
20134     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
20135     {
20136       75/jump-if-!= break/disp8
20137       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
20138     }
20139     # return (a->value == stream)
20140     81 7/subop/compare *(eax+4) 0xb/imm32/stream  # Type-tree-value
20141     0f 94/set-byte-if-= %al
20142     81 4/subop/and %eax 0xff/imm32
20143 $is-mu-stream-type?:end:
20144     # . epilogue
20145     89/<- %esp 5/r32/ebp
20146     5d/pop-to-ebp
20147     c3/return
20148 
20149 test-emit-subx-stmt-primitive:
20150     # Primitive operation on a variable on the stack.
20151     #   increment foo
20152     # =>
20153     #   ff 0/subop/increment *(ebp-8)
20154     #
20155     # There's a variable on the var stack as follows:
20156     #   name: 'foo'
20157     #   type: int
20158     #   stack-offset: -8
20159     #
20160     # There's a primitive with this info:
20161     #   name: 'increment'
20162     #   inouts: int/mem
20163     #   value: 'ff 0/subop/increment'
20164     #
20165     # . prologue
20166     55/push-ebp
20167     89/<- %ebp 4/r32/esp
20168     # setup
20169     (clear-stream _test-output-stream)
20170     (clear-stream $_test-output-buffered-file->buffer)
20171     # simulate allocated payloads starting with an initial fake alloc-id (0x11)
20172 $test-emit-subx-stmt-primitive:initialize-type:
20173     # var type/ecx: (payload type-tree) = int
20174     68/push 0/imm32/right:null
20175     68/push 0/imm32/right:null
20176     68/push 0/imm32/left:unused
20177     68/push 1/imm32/value:int
20178     68/push 1/imm32/is-atom?:true
20179     68/push 0x11/imm32/alloc-id:fake:payload
20180     89/<- %ecx 4/r32/esp
20181 $test-emit-subx-stmt-primitive:initialize-var:
20182     # var var-foo/ecx: (payload var) = var(type)
20183     68/push 0/imm32/no-register
20184     68/push 0/imm32/no-register
20185     68/push -8/imm32/stack-offset
20186     68/push 1/imm32/block-depth
20187     51/push-ecx/type
20188     68/push 0x11/imm32/alloc-id:fake
20189     68/push 0/imm32/name
20190     68/push 0/imm32/name
20191     68/push 0x11/imm32/alloc-id:fake:payload
20192     89/<- %ecx 4/r32/esp
20193 $test-emit-subx-stmt-primitive:initialize-var-name:
20194     # var-foo->name = "foo"
20195     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20196     (copy-array Heap "foo" %eax)
20197 $test-emit-subx-stmt-primitive:initialize-stmt-var:
20198     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
20199     68/push 0/imm32/is-deref:false
20200     68/push 0/imm32/next
20201     68/push 0/imm32/next
20202     51/push-ecx/var-foo
20203     68/push 0x11/imm32/alloc-id:fake
20204     68/push 0x11/imm32/alloc-id:fake:payload
20205     89/<- %ebx 4/r32/esp
20206 $test-emit-subx-stmt-primitive:initialize-stmt:
20207     # var stmt/esi: (addr statement)
20208     68/push 0/imm32/no-outputs
20209     68/push 0/imm32/no-outputs
20210     53/push-ebx/inouts
20211     68/push 0x11/imm32/alloc-id:fake
20212     68/push 0/imm32/operation
20213     68/push 0/imm32/operation
20214     68/push 1/imm32/tag
20215     89/<- %esi 4/r32/esp
20216 $test-emit-subx-stmt-primitive:initialize-stmt-operation:
20217     # stmt->operation = "increment"
20218     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20219     (copy-array Heap "increment" %eax)
20220 $test-emit-subx-stmt-primitive:initialize-primitive:
20221     # var primitives/ebx: (addr primitive)
20222     68/push 0/imm32/next
20223     68/push 0/imm32/next
20224     68/push 0/imm32/output-is-write-only
20225     68/push 0/imm32/no-disp32
20226     68/push 0/imm32/no-imm8
20227     68/push 0/imm32/no-imm32
20228     68/push 0/imm32/no-r32
20229     68/push 1/imm32/rm32-is-first-inout
20230     68/push 0/imm32/subx-name
20231     68/push 0/imm32/subx-name
20232     68/push 0/imm32/no-outputs
20233     68/push 0/imm32/no-outputs
20234     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
20235     68/push 0x11/imm32/alloc-id:fake
20236     68/push 0/imm32/name
20237     68/push 0/imm32/name
20238     89/<- %ebx 4/r32/esp
20239 $test-emit-subx-stmt-primitive:initialize-primitive-name:
20240     # primitives->name = "increment"
20241     (copy-array Heap "increment" %ebx)  # Primitive-name
20242 $test-emit-subx-stmt-primitive:initialize-primitive-subx-name:
20243     # primitives->subx-name = "ff 0/subop/increment"
20244     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
20245     (copy-array Heap "ff 0/subop/increment" %eax)
20246     # convert
20247     c7 0/subop/copy *Curr-block-depth 0/imm32
20248     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
20249     (flush _test-output-buffered-file)
20250 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20256     # check output
20257     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-stmt-primitive")
20258     # . epilogue
20259     89/<- %esp 5/r32/ebp
20260     5d/pop-to-ebp
20261     c3/return
20262 
20263 test-emit-subx-stmt-primitive-register:
20264     # Primitive operation on a variable in a register.
20265     #   foo <- increment
20266     # =>
20267     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
20268     #
20269     # There's a variable on the var stack as follows:
20270     #   name: 'foo'
20271     #   type: int
20272     #   register: 'eax'
20273     #
20274     # There's a primitive with this info:
20275     #   name: 'increment'
20276     #   out: int/reg
20277     #   value: 'ff 0/subop/increment'
20278     #
20279     # . prologue
20280     55/push-ebp
20281     89/<- %ebp 4/r32/esp
20282     # setup
20283     (clear-stream _test-output-stream)
20284     (clear-stream $_test-output-buffered-file->buffer)
20285 $test-emit-subx-stmt-primitive-register:initialize-type:
20286     # var type/ecx: (payload type-tree) = int
20287     68/push 0/imm32/right:null
20288     68/push 0/imm32/right:null
20289     68/push 0/imm32/left:unused
20290     68/push 1/imm32/value:int
20291     68/push 1/imm32/is-atom?:true
20292     68/push 0x11/imm32/alloc-id:fake:payload
20293     89/<- %ecx 4/r32/esp
20294 $test-emit-subx-stmt-primitive-register:initialize-var:
20295     # var var-foo/ecx: (payload var)
20296     68/push 0/imm32/register
20297     68/push 0/imm32/register
20298     68/push 0/imm32/no-stack-offset
20299     68/push 1/imm32/block-depth
20300     51/push-ecx
20301     68/push 0x11/imm32/alloc-id:fake
20302     68/push 0/imm32/name
20303     68/push 0/imm32/name
20304     68/push 0x11/imm32/alloc-id:fake:payload
20305     89/<- %ecx 4/r32/esp
20306 $test-emit-subx-stmt-primitive-register:initialize-var-name:
20307     # var-foo->name = "foo"
20308     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20309     (copy-array Heap "foo" %eax)
20310 $test-emit-subx-stmt-primitive-register:initialize-var-register:
20311     # var-foo->register = "eax"
20312     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
20313     (copy-array Heap "eax" %eax)
20314 $test-emit-subx-stmt-primitive-register:initialize-stmt-var:
20315     # var operand/ebx: (payload stmt-var)
20316     68/push 0/imm32/is-deref:false
20317     68/push 0/imm32/next
20318     68/push 0/imm32/next
20319     51/push-ecx/var-foo
20320     68/push 0x11/imm32/alloc-id:fake
20321     68/push 0x11/imm32/alloc-id:fake:payload
20322     89/<- %ebx 4/r32/esp
20323 $test-emit-subx-stmt-primitive-register:initialize-stmt:
20324     # var stmt/esi: (addr statement)
20325     53/push-ebx/outputs
20326     68/push 0x11/imm32/alloc-id:fake
20327     68/push 0/imm32/no-inouts
20328     68/push 0/imm32/no-inouts
20329     68/push 0/imm32/operation
20330     68/push 0/imm32/operation
20331     68/push 1/imm32
20332     89/<- %esi 4/r32/esp
20333 $test-emit-subx-stmt-primitive-register:initialize-stmt-operation:
20334     # stmt->operation = "increment"
20335     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20336     (copy-array Heap "increment" %eax)
20337 $test-emit-subx-stmt-primitive-register:initialize-formal-var:
20338     # var formal-var/ebx: (payload var)
20339     68/push 0/imm32/register
20340     68/push 0/imm32/register
20341     68/push 0/imm32/no-stack-offset
20342     68/push 1/imm32/block-depth
20343     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
20344     68/push 0x11/imm32/alloc-id:fake
20345     68/push 0/imm32/name
20346     68/push 0/imm32/name
20347     68/push 0x11/imm32/alloc-id:fake:payload
20348     89/<- %ebx 4/r32/esp
20349 $test-emit-subx-stmt-primitive-register:initialize-formal-var-name:
20350     # formal-var->name = "dummy"
20351     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
20352     (copy-array Heap "dummy" %eax)
20353 $test-emit-subx-stmt-primitive-register:initialize-formal-register:
20354     # formal-var->register = "*"
20355     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
20356     (copy-array Heap "*" %eax)  # Any-register
20357 $test-emit-subx-stmt-primitive-register:initialize-var-list:
20358     # var formal-outputs/ebx: (payload list var)
20359     68/push 0/imm32/next
20360     68/push 0/imm32/next
20361     53/push-ebx/formal-var
20362     68/push 0x11/imm32/alloc-id:fake
20363     68/push 0x11/imm32/alloc-id:fake:payload
20364     89/<- %ebx 4/r32/esp
20365 $test-emit-subx-stmt-primitive-register:initialize-primitive:
20366     # var primitives/ebx: (addr primitive)
20367     68/push 0/imm32/next
20368     68/push 0/imm32/next
20369     68/push 0/imm32/output-is-write-only
20370     68/push 0/imm32/no-disp32
20371     68/push 0/imm32/no-imm8
20372     68/push 0/imm32/no-imm32
20373     68/push 0/imm32/no-r32
20374     68/push 3/imm32/rm32-is-first-output
20375     68/push 0/imm32/subx-name
20376     68/push 0/imm32/subx-name
20377     53/push-ebx/outputs
20378     68/push 0x11/imm32/alloc-id:fake
20379     68/push 0/imm32/no-inouts
20380     68/push 0/imm32/no-inouts
20381     68/push 0/imm32/name
20382     68/push 0/imm32/name
20383     89/<- %ebx 4/r32/esp
20384 $test-emit-subx-stmt-primitive-register:initialize-primitive-name:
20385     # primitives->name = "increment"
20386     (copy-array Heap "increment" %ebx)  # Primitive-name
20387 $test-emit-subx-stmt-primitive-register:initialize-primitive-subx-name:
20388     # primitives->subx-name = "ff 0/subop/increment"
20389     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
20390     (copy-array Heap "ff 0/subop/increment" %eax)
20391     # convert
20392     c7 0/subop/copy *Curr-block-depth 0/imm32
20393     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
20394     (flush _test-output-buffered-file)
20395 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20401     # check output
20402     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-primitive-register")
20403     # . epilogue
20404     89/<- %esp 5/r32/ebp
20405     5d/pop-to-ebp
20406     c3/return
20407 
20408 test-emit-subx-stmt-select-primitive:
20409     # Select the right primitive between overloads.
20410     #   foo <- increment
20411     # =>
20412     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
20413     #
20414     # There's a variable on the var stack as follows:
20415     #   name: 'foo'
20416     #   type: int
20417     #   register: 'eax'
20418     #
20419     # There's two primitives, as follows:
20420     #   - name: 'increment'
20421     #     out: int/reg
20422     #     value: 'ff 0/subop/increment'
20423     #   - name: 'increment'
20424     #     inout: int/mem
20425     #     value: 'ff 0/subop/increment'
20426     #
20427     # . prologue
20428     55/push-ebp
20429     89/<- %ebp 4/r32/esp
20430     # setup
20431     (clear-stream _test-output-stream)
20432     (clear-stream $_test-output-buffered-file->buffer)
20433 $test-emit-subx-stmt-select-primitive:initialize-type:
20434     # var type/ecx: (payload type-tree) = int
20435     68/push 0/imm32/right:null
20436     68/push 0/imm32/right:null
20437     68/push 0/imm32/left:unused
20438     68/push 1/imm32/value:int
20439     68/push 1/imm32/is-atom?:true
20440     68/push 0x11/imm32/alloc-id:fake:payload
20441     89/<- %ecx 4/r32/esp
20442 $test-emit-subx-stmt-select-primitive:initialize-var:
20443     # var var-foo/ecx: (payload var)
20444     68/push 0/imm32/register
20445     68/push 0/imm32/register
20446     68/push 0/imm32/no-stack-offset
20447     68/push 1/imm32/block-depth
20448     51/push-ecx
20449     68/push 0x11/imm32/alloc-id:fake
20450     68/push 0/imm32/name
20451     68/push 0/imm32/name
20452     68/push 0x11/imm32/alloc-id:fake:payload
20453     89/<- %ecx 4/r32/esp
20454 $test-emit-subx-stmt-select-primitive:initialize-var-name:
20455     # var-foo->name = "foo"
20456     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20457     (copy-array Heap "foo" %eax)
20458 $test-emit-subx-stmt-select-primitive:initialize-var-register:
20459     # var-foo->register = "eax"
20460     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
20461     (copy-array Heap "eax" %eax)
20462 $test-emit-subx-stmt-select-primitive:initialize-stmt-var:
20463     # var operand/ebx: (payload stmt-var)
20464     68/push 0/imm32/is-deref:false
20465     68/push 0/imm32/next
20466     68/push 0/imm32/next
20467     51/push-ecx/var-foo
20468     68/push 0x11/imm32/alloc-id:fake
20469     68/push 0x11/imm32/alloc-id:fake:payload
20470     89/<- %ebx 4/r32/esp
20471 $test-emit-subx-stmt-select-primitive:initialize-stmt:
20472     # var stmt/esi: (addr statement)
20473     53/push-ebx/outputs
20474     68/push 0x11/imm32/alloc-id:fake
20475     68/push 0/imm32/no-inouts
20476     68/push 0/imm32/no-inouts
20477     68/push 0/imm32/operation
20478     68/push 0/imm32/operation
20479     68/push 1/imm32
20480     89/<- %esi 4/r32/esp
20481 $test-emit-subx-stmt-select-primitive:initialize-stmt-operation:
20482     # stmt->operation = "increment"
20483     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20484     (copy-array Heap "increment" %eax)
20485 $test-emit-subx-stmt-select-primitive:initialize-formal-var:
20486     # var formal-var/ebx: (payload var)
20487     68/push 0/imm32/register
20488     68/push 0/imm32/register
20489     68/push 0/imm32/no-stack-offset
20490     68/push 1/imm32/block-depth
20491     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
20492     68/push 0x11/imm32/alloc-id:fake
20493     68/push 0/imm32/name
20494     68/push 0/imm32/name
20495     68/push 0x11/imm32/alloc-id:fake:payload
20496     89/<- %ebx 4/r32/esp
20497 $test-emit-subx-stmt-select-primitive:initialize-formal-var-name:
20498     # formal-var->name = "dummy"
20499     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
20500     (copy-array Heap "dummy" %eax)
20501 $test-emit-subx-stmt-select-primitive:initialize-formal-register:
20502     # formal-var->register = "*"
20503     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
20504     (copy-array Heap "*" %eax)  # Any-register
20505 $test-emit-subx-stmt-select-primitive:initialize-var-list:
20506     # var formal-outputs/ebx: (payload list var)
20507     68/push 0/imm32/next
20508     68/push 0/imm32/next
20509     53/push-ebx/formal-var
20510     68/push 0x11/imm32/alloc-id:fake
20511     68/push 0x11/imm32/alloc-id:fake:payload
20512     89/<- %ebx 4/r32/esp
20513 $test-emit-subx-stmt-select-primitive:initialize-primitive2:
20514     # var primitive2/edi: (payload primitive)
20515     68/push 0/imm32/next
20516     68/push 0/imm32/next
20517     68/push 0/imm32/output-is-write-only
20518     68/push 0/imm32/no-disp32
20519     68/push 0/imm32/no-imm8
20520     68/push 0/imm32/no-imm32
20521     68/push 0/imm32/no-r32
20522     68/push 3/imm32/rm32-is-first-output
20523     68/push 0/imm32/subx-name
20524     68/push 0/imm32/subx-name
20525     53/push-ebx/outputs
20526     68/push 0x11/imm32/alloc-id:fake
20527     68/push 0/imm32/no-inouts
20528     68/push 0/imm32/no-inouts
20529     68/push 0/imm32/name
20530     68/push 0/imm32/name
20531     68/push 0x11/imm32/alloc-id:fake:payload
20532     89/<- %edi 4/r32/esp
20533 $test-emit-subx-stmt-select-primitive:initialize-primitive2-name:
20534     # primitives->name = "increment"
20535     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
20536     (copy-array Heap "increment" %eax)
20537 $test-emit-subx-stmt-select-primitive:initialize-primitive2-subx-name:
20538     # primitives->subx-name = "ff 0/subop/increment"
20539     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
20540     (copy-array Heap "ff 0/subop/increment" %eax)
20541 $test-emit-subx-stmt-select-primitive:initialize-primitive:
20542     # var primitives/ebx: (addr primitive)
20543     57/push-edi
20544     68/push 0x11/imm32/alloc-id:fake
20545     68/push 0/imm32/output-is-write-only
20546     68/push 0/imm32/no-disp32
20547     68/push 0/imm32/no-imm8
20548     68/push 0/imm32/no-imm32
20549     68/push 0/imm32/no-r32
20550     68/push 1/imm32/rm32-is-first-inout
20551     68/push 0/imm32/subx-name
20552     68/push 0/imm32/subx-name
20553     68/push 0/imm32/no-outputs
20554     68/push 0/imm32/no-outputs
20555     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
20556     68/push 0x11/imm32/alloc-id:fake
20557     68/push 0/imm32/name
20558     68/push 0/imm32/name
20559     89/<- %ebx 4/r32/esp
20560 $test-emit-subx-stmt-select-primitive:initialize-primitive-name:
20561     # primitives->name = "increment"
20562     (copy-array Heap "increment" %ebx)  # Primitive-name
20563 $test-emit-subx-stmt-select-primitive:initialize-primitive-subx-name:
20564     # primitives->subx-name = "ff 0/subop/increment"
20565     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
20566     (copy-array Heap "ff 0/subop/increment" %eax)
20567     # convert
20568     c7 0/subop/copy *Curr-block-depth 0/imm32
20569     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
20570     (flush _test-output-buffered-file)
20571 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20577     # check output
20578     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive")
20579     # . epilogue
20580     89/<- %esp 5/r32/ebp
20581     5d/pop-to-ebp
20582     c3/return
20583 
20584 test-emit-subx-stmt-select-primitive-2:
20585     # Select the right primitive between overloads.
20586     #   increment foo
20587     # =>
20588     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
20589     #
20590     # There's a variable on the var stack as follows:
20591     #   name: 'foo'
20592     #   type: int
20593     #   register: 'eax'
20594     #
20595     # There's two primitives, as follows:
20596     #   - name: 'increment'
20597     #     out: int/reg
20598     #     value: 'ff 0/subop/increment'
20599     #   - name: 'increment'
20600     #     inout: int/mem
20601     #     value: 'ff 0/subop/increment'
20602     #
20603     # . prologue
20604     55/push-ebp
20605     89/<- %ebp 4/r32/esp
20606     # setup
20607     (clear-stream _test-output-stream)
20608     (clear-stream $_test-output-buffered-file->buffer)
20609 $test-emit-subx-stmt-select-primitive-2:initialize-type:
20610     # var type/ecx: (payload type-tree) = int
20611     68/push 0/imm32/right:null
20612     68/push 0/imm32/right:null
20613     68/push 0/imm32/left:unused
20614     68/push 1/imm32/value:int
20615     68/push 1/imm32/is-atom?:true
20616     68/push 0x11/imm32/alloc-id:fake:payload
20617     89/<- %ecx 4/r32/esp
20618 $test-emit-subx-stmt-select-primitive-2:initialize-var:
20619     # var var-foo/ecx: (payload var)
20620     68/push 0/imm32/register
20621     68/push 0/imm32/register
20622     68/push 0/imm32/no-stack-offset
20623     68/push 1/imm32/block-depth
20624     51/push-ecx
20625     68/push 0x11/imm32/alloc-id:fake
20626     68/push 0/imm32/name
20627     68/push 0/imm32/name
20628     68/push 0x11/imm32/alloc-id:fake:payload
20629     89/<- %ecx 4/r32/esp
20630 $test-emit-subx-stmt-select-primitive-2:initialize-var-name:
20631     # var-foo->name = "foo"
20632     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20633     (copy-array Heap "foo" %eax)
20634 $test-emit-subx-stmt-select-primitive-2:initialize-var-register:
20635     # var-foo->register = "eax"
20636     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
20637     (copy-array Heap "eax" %eax)
20638 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-var:
20639     # var operand/ebx: (payload stmt-var)
20640     68/push 0/imm32/is-deref:false
20641     68/push 0/imm32/next
20642     68/push 0/imm32/next
20643     51/push-ecx/var-foo
20644     68/push 0x11/imm32/alloc-id:fake
20645     68/push 0x11/imm32/alloc-id:fake:payload
20646     89/<- %ebx 4/r32/esp
20647 $test-emit-subx-stmt-select-primitive-2:initialize-stmt:
20648     # var stmt/esi: (addr statement)
20649     68/push 0/imm32/no-outputs
20650     68/push 0/imm32/no-outputs
20651     53/push-ebx/inouts
20652     68/push 0x11/imm32/alloc-id:fake
20653     68/push 0/imm32/operation
20654     68/push 0/imm32/operation
20655     68/push 1/imm32
20656     89/<- %esi 4/r32/esp
20657 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-operation:
20658     # stmt->operation = "increment"
20659     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20660     (copy-array Heap "increment" %eax)
20661 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var:
20662     # var formal-var/ebx: (payload var)
20663     68/push 0/imm32/register
20664     68/push 0/imm32/register
20665     68/push 0/imm32/no-stack-offset
20666     68/push 1/imm32/block-depth
20667     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
20668     68/push 0x11/imm32/alloc-id:fake
20669     68/push 0/imm32/name
20670     68/push 0/imm32/name
20671     68/push 0x11/imm32/alloc-id:fake:payload
20672     89/<- %ebx 4/r32/esp
20673 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var-name:
20674     # formal-var->name = "dummy"
20675     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
20676     (copy-array Heap "dummy" %eax)
20677 $test-emit-subx-stmt-select-primitive-2:initialize-formal-register:
20678     # formal-var->register = "*"
20679     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
20680     (copy-array Heap "*" %eax)  # Any-register
20681 $test-emit-subx-stmt-select-primitive-2:initialize-var-list:
20682     # var formal-outputs/ebx: (payload list stmt-var)
20683     68/push 0/imm32/next
20684     68/push 0/imm32/next
20685     53/push-ebx/formal-var
20686     68/push 0x11/imm32/alloc-id:fake
20687     68/push 0x11/imm32/alloc-id:fake:payload
20688     89/<- %ebx 4/r32/esp
20689 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2:
20690     # var primitive2/edi: (payload primitive)
20691     68/push 0/imm32/next
20692     68/push 0/imm32/next
20693     68/push 0/imm32/output-is-write-only
20694     68/push 0/imm32/no-disp32
20695     68/push 0/imm32/no-imm8
20696     68/push 0/imm32/no-imm32
20697     68/push 0/imm32/no-r32
20698     68/push 3/imm32/rm32-is-first-output
20699     68/push 0/imm32/subx-name
20700     68/push 0/imm32/subx-name
20701     53/push-ebx/outputs
20702     68/push 0x11/imm32/alloc-id:fake
20703     68/push 0/imm32/no-inouts
20704     68/push 0/imm32/no-inouts
20705     68/push 0/imm32/name
20706     68/push 0/imm32/name
20707     68/push 0x11/imm32/alloc-id:fake:payload
20708     89/<- %edi 4/r32/esp
20709 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-name:
20710     # primitives->name = "increment"
20711     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
20712     (copy-array Heap "increment" %eax)
20713 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-subx-name:
20714     # primitives->subx-name = "ff 0/subop/increment"
20715     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
20716     (copy-array Heap "ff 0/subop/increment" %eax)
20717 $test-emit-subx-stmt-select-primitive-2:initialize-primitive:
20718     # var primitives/ebx: (addr primitive)
20719     57/push-edi
20720     68/push 0x11/imm32/alloc-id:fake
20721     68/push 0/imm32/output-is-write-only
20722     68/push 0/imm32/no-disp32
20723     68/push 0/imm32/no-imm8
20724     68/push 0/imm32/no-imm32
20725     68/push 0/imm32/no-r32
20726     68/push 1/imm32/rm32-is-first-inout
20727     68/push 0/imm32/subx-name
20728     68/push 0/imm32/subx-name
20729     68/push 0/imm32/no-outputs
20730     68/push 0/imm32/no-outputs
20731     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
20732     68/push 0x11/imm32/alloc-id:fake
20733     68/push 0/imm32/name
20734     68/push 0/imm32/name
20735     89/<- %ebx 4/r32/esp
20736 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-name:
20737     # primitives->name = "increment"
20738     (copy-array Heap "increment" %ebx)  # Primitive-name
20739 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-subx-name:
20740     # primitives->subx-name = "ff 0/subop/increment"
20741     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
20742     (copy-array Heap "ff 0/subop/increment" %eax)
20743     # convert
20744     c7 0/subop/copy *Curr-block-depth 0/imm32
20745     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
20746     (flush _test-output-buffered-file)
20747 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20753     # check output
20754     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive-2")
20755     # . epilogue
20756     89/<- %esp 5/r32/ebp
20757     5d/pop-to-ebp
20758     c3/return
20759 
20760 test-increment-register:
20761     # Select the right register between overloads.
20762     #   foo <- increment
20763     # =>
20764     #   50/increment-eax
20765     #
20766     # There's a variable on the var stack as follows:
20767     #   name: 'foo'
20768     #   type: int
20769     #   register: 'eax'
20770     #
20771     # Primitives are the global definitions.
20772     #
20773     # . prologue
20774     55/push-ebp
20775     89/<- %ebp 4/r32/esp
20776     # setup
20777     (clear-stream _test-output-stream)
20778     (clear-stream $_test-output-buffered-file->buffer)
20779 $test-increment-register:initialize-type:
20780     # var type/ecx: (payload type-tree) = int
20781     68/push 0/imm32/right:null
20782     68/push 0/imm32/right:null
20783     68/push 0/imm32/left:unused
20784     68/push 1/imm32/value:int
20785     68/push 1/imm32/is-atom?:true
20786     68/push 0x11/imm32/alloc-id:fake:payload
20787     89/<- %ecx 4/r32/esp
20788 $test-increment-register:initialize-var:
20789     # var var-foo/ecx: (payload var)
20790     68/push 0/imm32/register
20791     68/push 0/imm32/register
20792     68/push 0/imm32/no-stack-offset
20793     68/push 1/imm32/block-depth
20794     51/push-ecx
20795     68/push 0x11/imm32/alloc-id:fake
20796     68/push 0/imm32/name
20797     68/push 0/imm32/name
20798     68/push 0x11/imm32/alloc-id:fake:payload
20799     89/<- %ecx 4/r32/esp
20800 $test-increment-register:initialize-var-name:
20801     # var-foo->name = "foo"
20802     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20803     (copy-array Heap "foo" %eax)
20804 $test-increment-register:initialize-var-register:
20805     # var-foo->register = "eax"
20806     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
20807     (copy-array Heap "eax" %eax)
20808 $test-increment-register:initialize-stmt-var:
20809     # var operand/ebx: (payload stmt-var)
20810     68/push 0/imm32/is-deref:false
20811     68/push 0/imm32/next
20812     68/push 0/imm32/next
20813     51/push-ecx/var-foo
20814     68/push 0x11/imm32/alloc-id:fake
20815     68/push 0x11/imm32/alloc-id:fake:payload
20816     89/<- %ebx 4/r32/esp
20817 $test-increment-register:initialize-stmt:
20818     # var stmt/esi: (addr statement)
20819     53/push-ebx/outputs
20820     68/push 0x11/imm32/alloc-id:fake
20821     68/push 0/imm32/no-inouts
20822     68/push 0/imm32/no-inouts
20823     68/push 0/imm32/operation
20824     68/push 0/imm32/operation
20825     68/push 1/imm32
20826     89/<- %esi 4/r32/esp
20827 $test-increment-register:initialize-stmt-operation:
20828     # stmt->operation = "increment"
20829     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20830     (copy-array Heap "increment" %eax)
20831     # convert
20832     c7 0/subop/copy *Curr-block-depth 0/imm32
20833     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
20834     (flush _test-output-buffered-file)
20835 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20841     # check output
20842     (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register")
20843     # . epilogue
20844     89/<- %esp 5/r32/ebp
20845     5d/pop-to-ebp
20846     c3/return
20847 
20848 test-add-reg-to-reg:
20849     #   var1/reg <- add var2/reg
20850     # =>
20851     #   01/add-to %var1 var2
20852     #
20853     # . prologue
20854     55/push-ebp
20855     89/<- %ebp 4/r32/esp
20856     # setup
20857     (clear-stream _test-output-stream)
20858     (clear-stream $_test-output-buffered-file->buffer)
20859 $test-add-reg-to-reg:initialize-type:
20860     # var type/ecx: (payload type-tree) = int
20861     68/push 0/imm32/right:null
20862     68/push 0/imm32/right:null
20863     68/push 0/imm32/left:unused
20864     68/push 1/imm32/value:int
20865     68/push 1/imm32/is-atom?:true
20866     68/push 0x11/imm32/alloc-id:fake:payload
20867     89/<- %ecx 4/r32/esp
20868 $test-add-reg-to-reg:initialize-var1:
20869     # var var1/ecx: (payload var)
20870     68/push 0/imm32/register
20871     68/push 0/imm32/register
20872     68/push 0/imm32/no-stack-offset
20873     68/push 1/imm32/block-depth
20874     51/push-ecx
20875     68/push 0x11/imm32/alloc-id:fake
20876     68/push 0/imm32/name
20877     68/push 0/imm32/name
20878     68/push 0x11/imm32/alloc-id:fake:payload
20879     89/<- %ecx 4/r32/esp
20880 $test-add-reg-to-reg:initialize-var1-name:
20881     # var1->name = "var1"
20882     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20883     (copy-array Heap "var1" %eax)
20884 $test-add-reg-to-reg:initialize-var1-register:
20885     # var1->register = "eax"
20886     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
20887     (copy-array Heap "eax" %eax)
20888 $test-add-reg-to-reg:initialize-var2:
20889     # var var2/edx: (payload var)
20890     68/push 0/imm32/register
20891     68/push 0/imm32/register
20892     68/push 0/imm32/no-stack-offset
20893     68/push 1/imm32/block-depth
20894     ff 6/subop/push *(ecx+0x10)
20895     68/push 0x11/imm32/alloc-id:fake
20896     68/push 0/imm32/name
20897     68/push 0/imm32/name
20898     68/push 0x11/imm32/alloc-id:fake:payload
20899     89/<- %edx 4/r32/esp
20900 $test-add-reg-to-reg:initialize-var2-name:
20901     # var2->name = "var2"
20902     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
20903     (copy-array Heap "var2" %eax)
20904 $test-add-reg-to-reg:initialize-var2-register:
20905     # var2->register = "ecx"
20906     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
20907     (copy-array Heap "ecx" %eax)
20908 $test-add-reg-to-reg:initialize-inouts:
20909     # var inouts/esi: (payload stmt-var) = [var2]
20910     68/push 0/imm32/is-deref:false
20911     68/push 0/imm32/next
20912     68/push 0/imm32/next
20913     52/push-edx/var2
20914     68/push 0x11/imm32/alloc-id:fake
20915     68/push 0x11/imm32/alloc-id:fake:payload
20916     89/<- %esi 4/r32/esp
20917 $test-add-reg-to-reg:initialize-outputs:
20918     # var outputs/edi: (payload stmt-var) = [var1]
20919     68/push 0/imm32/is-deref:false
20920     68/push 0/imm32/next
20921     68/push 0/imm32/next
20922     51/push-ecx/var1
20923     68/push 0x11/imm32/alloc-id:fake
20924     68/push 0x11/imm32/alloc-id:fake:payload
20925     89/<- %edi 4/r32/esp
20926 $test-add-reg-to-reg:initialize-stmt:
20927     # var stmt/esi: (addr statement)
20928     68/push 0/imm32/next
20929     68/push 0/imm32/next
20930     57/push-edi/outputs
20931     68/push 0x11/imm32/alloc-id:fake
20932     56/push-esi/inouts
20933     68/push 0x11/imm32/alloc-id:fake
20934     68/push 0/imm32/operation
20935     68/push 0/imm32/operation
20936     68/push 1/imm32/tag:stmt1
20937     89/<- %esi 4/r32/esp
20938 $test-add-reg-to-reg:initialize-stmt-operation:
20939     # stmt->operation = "add"
20940     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20941     (copy-array Heap "add" %eax)
20942     # convert
20943     c7 0/subop/copy *Curr-block-depth 0/imm32
20944     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
20945     (flush _test-output-buffered-file)
20946 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20952     # check output
20953     (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg")
20954     # . epilogue
20955     89/<- %esp 5/r32/ebp
20956     5d/pop-to-ebp
20957     c3/return
20958 
20959 test-add-reg-to-mem:
20960     #   add-to var1 var2/reg
20961     # =>
20962     #   01/add-to *(ebp+__) var2
20963     #
20964     # . prologue
20965     55/push-ebp
20966     89/<- %ebp 4/r32/esp
20967     # setup
20968     (clear-stream _test-output-stream)
20969     (clear-stream $_test-output-buffered-file->buffer)
20970 $test-add-reg-to-mem:initialize-type:
20971     # var type/ecx: (payload type-tree) = int
20972     68/push 0/imm32/right:null
20973     68/push 0/imm32/right:null
20974     68/push 0/imm32/left:unused
20975     68/push 1/imm32/value:int
20976     68/push 1/imm32/is-atom?:true
20977     68/push 0x11/imm32/alloc-id:fake:payload
20978     89/<- %ecx 4/r32/esp
20979 $test-add-reg-to-mem:initialize-var1:
20980     # var var1/ecx: (payload var)
20981     68/push 0/imm32/register
20982     68/push 0/imm32/register
20983     68/push 8/imm32/stack-offset
20984     68/push 1/imm32/block-depth
20985     51/push-ecx
20986     68/push 0x11/imm32/alloc-id:fake
20987     68/push 0/imm32/name
20988     68/push 0/imm32/name
20989     68/push 0x11/imm32/alloc-id:fake:payload
20990     89/<- %ecx 4/r32/esp
20991 $test-add-reg-to-mem:initialize-var1-name:
20992     # var1->name = "var1"
20993     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20994     (copy-array Heap "var1" %eax)
20995 $test-add-reg-to-mem:initialize-var2:
20996     # var var2/edx: (payload var)
20997     68/push 0/imm32/register
20998     68/push 0/imm32/register
20999     68/push 0/imm32/no-stack-offset
21000     68/push 1/imm32/block-depth
21001     ff 6/subop/push *(ecx+0x10)
21002     68/push 0x11/imm32/alloc-id:fake
21003     68/push 0/imm32/name
21004     68/push 0/imm32/name
21005     68/push 0x11/imm32/alloc-id:fake:payload
21006     89/<- %edx 4/r32/esp
21007 $test-add-reg-to-mem:initialize-var2-name:
21008     # var2->name = "var2"
21009     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21010     (copy-array Heap "var2" %eax)
21011 $test-add-reg-to-mem:initialize-var2-register:
21012     # var2->register = "ecx"
21013     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
21014     (copy-array Heap "ecx" %eax)
21015 $test-add-reg-to-mem:initialize-inouts:
21016     # var inouts/esi: (payload stmt-var) = [var2]
21017     68/push 0/imm32/is-deref:false
21018     68/push 0/imm32/next
21019     68/push 0/imm32/next
21020     52/push-edx/var2
21021     68/push 0x11/imm32/alloc-id:fake
21022     68/push 0x11/imm32/alloc-id:fake:payload
21023     89/<- %esi 4/r32/esp
21024     # inouts = [var1, var2]
21025     68/push 0/imm32/is-deref:false
21026     56/push-esi/next
21027     68/push 0x11/imm32/alloc-id:fake
21028     51/push-ecx/var1
21029     68/push 0x11/imm32/alloc-id:fake
21030     68/push 0x11/imm32/alloc-id:fake:payload
21031     89/<- %esi 4/r32/esp
21032 $test-add-reg-to-mem:initialize-stmt:
21033     # var stmt/esi: (addr statement)
21034     68/push 0/imm32/next
21035     68/push 0/imm32/next
21036     68/push 0/imm32/outputs
21037     68/push 0/imm32/outputs
21038     56/push-esi/inouts
21039     68/push 0x11/imm32/alloc-id:fake
21040     68/push 0/imm32/operation
21041     68/push 0/imm32/operation
21042     68/push 1/imm32/tag:stmt1
21043     89/<- %esi 4/r32/esp
21044 $test-add-reg-to-mem:initialize-stmt-operation:
21045     # stmt->operation = "add-to"
21046     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21047     (copy-array Heap "add-to" %eax)
21048     # convert
21049     c7 0/subop/copy *Curr-block-depth 0/imm32
21050     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21051     (flush _test-output-buffered-file)
21052 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21058     # check output
21059     (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem")
21060     # . epilogue
21061     89/<- %esp 5/r32/ebp
21062     5d/pop-to-ebp
21063     c3/return
21064 
21065 test-add-mem-to-reg:
21066     #   var1/reg <- add var2
21067     # =>
21068     #   03/add *(ebp+__) var1
21069     #
21070     # . prologue
21071     55/push-ebp
21072     89/<- %ebp 4/r32/esp
21073     # setup
21074     (clear-stream _test-output-stream)
21075     (clear-stream $_test-output-buffered-file->buffer)
21076 $test-add-mem-to-reg:initialize-type:
21077     # var type/ecx: (payload type-tree) = int
21078     68/push 0/imm32/right:null
21079     68/push 0/imm32/right:null
21080     68/push 0/imm32/left:unused
21081     68/push 1/imm32/value:int
21082     68/push 1/imm32/is-atom?:true
21083     68/push 0x11/imm32/alloc-id:fake:payload
21084     89/<- %ecx 4/r32/esp
21085 $test-add-mem-to-reg:initialize-var:
21086     # var var1/ecx: (payload var)
21087     68/push 0/imm32/register
21088     68/push 0/imm32/register
21089     68/push 0/imm32/no-stack-offset
21090     68/push 1/imm32/block-depth
21091     51/push-ecx
21092     68/push 0x11/imm32/alloc-id:fake
21093     68/push 0/imm32/name
21094     68/push 0/imm32/name
21095     68/push 0x11/imm32/alloc-id:fake:payload
21096     89/<- %ecx 4/r32/esp
21097 $test-add-mem-to-reg:initialize-var-name:
21098     # var1->name = "foo"
21099     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21100     (copy-array Heap "var1" %eax)
21101 $test-add-mem-to-reg:initialize-var-register:
21102     # var1->register = "eax"
21103     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
21104     (copy-array Heap "eax" %eax)
21105 $test-add-mem-to-reg:initialize-var2:
21106     # var var2/edx: (payload var)
21107     68/push 0/imm32/register
21108     68/push 0/imm32/register
21109     68/push 8/imm32/stack-offset
21110     68/push 1/imm32/block-depth
21111     ff 6/subop/push *(ecx+0x10)
21112     68/push 0x11/imm32/alloc-id:fake
21113     68/push 0/imm32/name
21114     68/push 0/imm32/name
21115     68/push 0x11/imm32/alloc-id:fake:payload
21116     89/<- %edx 4/r32/esp
21117 $test-add-mem-to-reg:initialize-var2-name:
21118     # var2->name = "var2"
21119     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21120     (copy-array Heap "var2" %eax)
21121 $test-add-mem-to-reg:initialize-inouts:
21122     # var inouts/esi: (payload stmt-var) = [var2]
21123     68/push 0/imm32/is-deref:false
21124     68/push 0/imm32/next
21125     68/push 0/imm32/next
21126     52/push-edx/var2
21127     68/push 0x11/imm32/alloc-id:fake
21128     68/push 0x11/imm32/alloc-id:fake:payload
21129     89/<- %esi 4/r32/esp
21130 $test-add-mem-to-reg:initialize-outputs:
21131     # var outputs/edi: (payload stmt-var) = [var1]
21132     68/push 0/imm32/is-deref:false
21133     68/push 0/imm32/next
21134     68/push 0/imm32/next
21135     51/push-ecx/var1
21136     68/push 0x11/imm32/alloc-id:fake
21137     68/push 0x11/imm32/alloc-id:fake:payload
21138     89/<- %edi 4/r32/esp
21139 $test-add-mem-to-reg:initialize-stmt:
21140     # var stmt/esi: (addr statement)
21141     68/push 0/imm32/next
21142     68/push 0/imm32/next
21143     57/push-edi/outputs
21144     68/push 0x11/imm32/alloc-id:fake
21145     56/push-esi/inouts
21146     68/push 0x11/imm32/alloc-id:fake
21147     68/push 0/imm32/operation
21148     68/push 0/imm32/operation
21149     68/push 1/imm32/tag:stmt1
21150     89/<- %esi 4/r32/esp
21151 $test-add-mem-to-reg:initialize-stmt-operation:
21152     # stmt->operation = "add"
21153     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21154     (copy-array Heap "add" %eax)
21155     # convert
21156     c7 0/subop/copy *Curr-block-depth 0/imm32
21157     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21158     (flush _test-output-buffered-file)
21159 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21165     # check output
21166     (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg")
21167     # . epilogue
21168     89/<- %esp 5/r32/ebp
21169     5d/pop-to-ebp
21170     c3/return
21171 
21172 test-add-literal-to-eax:
21173     #   var1/eax <- add 0x34
21174     # =>
21175     #   05/add-to-eax 0x34/imm32
21176     #
21177     # . prologue
21178     55/push-ebp
21179     89/<- %ebp 4/r32/esp
21180     # setup
21181     (clear-stream _test-output-stream)
21182     (clear-stream $_test-output-buffered-file->buffer)
21183 $test-add-literal-to-eax:initialize-var-type:
21184     # var type/ecx: (payload type-tree) = int
21185     68/push 0/imm32/right:null
21186     68/push 0/imm32/right:null
21187     68/push 0/imm32/left:unused
21188     68/push 1/imm32/value:int
21189     68/push 1/imm32/is-atom?:true
21190     68/push 0x11/imm32/alloc-id:fake:payload
21191     89/<- %ecx 4/r32/esp
21192 $test-add-literal-to-eax:initialize-var:
21193     # var v/ecx: (payload var)
21194     68/push 0/imm32/register
21195     68/push 0/imm32/register
21196     68/push 0/imm32/no-stack-offset
21197     68/push 1/imm32/block-depth
21198     51/push-ecx
21199     68/push 0x11/imm32/alloc-id:fake
21200     68/push 0/imm32/name
21201     68/push 0/imm32/name
21202     68/push 0x11/imm32/alloc-id:fake:payload
21203     89/<- %ecx 4/r32/esp
21204 $test-add-literal-to-eax:initialize-var-name:
21205     # v->name = "v"
21206     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21207     (copy-array Heap "v" %eax)
21208 $test-add-literal-to-eax:initialize-var-register:
21209     # v->register = "eax"
21210     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
21211     (copy-array Heap "eax" %eax)
21212 $test-add-literal-to-eax:initialize-literal-type:
21213     # var type/edx: (payload type-tree) = literal
21214     68/push 0/imm32/right:null
21215     68/push 0/imm32/right:null
21216     68/push 0/imm32/left:unused
21217     68/push 0/imm32/value:literal
21218     68/push 1/imm32/is-atom?:true
21219     68/push 0x11/imm32/alloc-id:fake:payload
21220     89/<- %edx 4/r32/esp
21221 $test-add-literal-to-eax:initialize-literal:
21222     # var l/edx: (payload var)
21223     68/push 0/imm32/register
21224     68/push 0/imm32/register
21225     68/push 0/imm32/no-stack-offset
21226     68/push 1/imm32/block-depth
21227     52/push-edx
21228     68/push 0x11/imm32/alloc-id:fake
21229     68/push 0/imm32/name
21230     68/push 0/imm32/name
21231     68/push 0x11/imm32/alloc-id:fake:payload
21232     89/<- %edx 4/r32/esp
21233 $test-add-literal-to-eax:initialize-literal-value:
21234     # l->name = "0x34"
21235     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21236     (copy-array Heap "0x34" %eax)
21237 $test-add-literal-to-eax:initialize-inouts:
21238     # var inouts/esi: (payload stmt-var) = [l]
21239     68/push 0/imm32/is-deref:false
21240     68/push 0/imm32/next
21241     68/push 0/imm32/next
21242     52/push-edx/l
21243     68/push 0x11/imm32/alloc-id:fake
21244     68/push 0x11/imm32/alloc-id:fake:payload
21245     89/<- %esi 4/r32/esp
21246 $test-add-literal-to-eax:initialize-outputs:
21247     # var outputs/edi: (payload stmt-var) = [v]
21248     68/push 0/imm32/is-deref:false
21249     68/push 0/imm32/next
21250     68/push 0/imm32/next
21251     51/push-ecx/v
21252     68/push 0x11/imm32/alloc-id:fake
21253     68/push 0x11/imm32/alloc-id:fake:payload
21254     89/<- %edi 4/r32/esp
21255 $test-add-literal-to-eax:initialize-stmt:
21256     # var stmt/esi: (addr statement)
21257     68/push 0/imm32/next
21258     68/push 0/imm32/next
21259     57/push-edi/outputs
21260     68/push 0x11/imm32/alloc-id:fake
21261     56/push-esi/inouts
21262     68/push 0x11/imm32/alloc-id:fake
21263     68/push 0/imm32/operation
21264     68/push 0/imm32/operation
21265     68/push 1/imm32/tag:stmt1
21266     89/<- %esi 4/r32/esp
21267 $test-add-literal-to-eax:initialize-stmt-operation:
21268     # stmt->operation = "add"
21269     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21270     (copy-array Heap "add" %eax)
21271     # convert
21272     c7 0/subop/copy *Curr-block-depth 0/imm32
21273     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21274     (flush _test-output-buffered-file)
21275 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21281     # check output
21282     (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax")
21283     # . epilogue
21284     89/<- %esp 5/r32/ebp
21285     5d/pop-to-ebp
21286     c3/return
21287 
21288 test-add-literal-to-reg:
21289     #   var1/ecx <- add 0x34
21290     # =>
21291     #   81 0/subop/add %ecx 0x34/imm32
21292     #
21293     # . prologue
21294     55/push-ebp
21295     89/<- %ebp 4/r32/esp
21296     # setup
21297     (clear-stream _test-output-stream)
21298     (clear-stream $_test-output-buffered-file->buffer)
21299 $test-add-literal-to-reg:initialize-var-type:
21300     # var type/ecx: (payload type-tree) = int
21301     68/push 0/imm32/right:null
21302     68/push 0/imm32/right:null
21303     68/push 0/imm32/left:unused
21304     68/push 1/imm32/value:int
21305     68/push 1/imm32/is-atom?:true
21306     68/push 0x11/imm32/alloc-id:fake:payload
21307     89/<- %ecx 4/r32/esp
21308 $test-add-literal-to-reg:initialize-var:
21309     # var v/ecx: (payload var)
21310     68/push 0/imm32/register
21311     68/push 0/imm32/register
21312     68/push 0/imm32/no-stack-offset
21313     68/push 1/imm32/block-depth
21314     51/push-ecx
21315     68/push 0x11/imm32/alloc-id:fake
21316     68/push 0/imm32/name
21317     68/push 0/imm32/name
21318     68/push 0x11/imm32/alloc-id:fake:payload
21319     89/<- %ecx 4/r32/esp
21320 $test-add-literal-to-reg:initialize-var-name:
21321     # v->name = "v"
21322     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21323     (copy-array Heap "v" %eax)
21324 $test-add-literal-to-reg:initialize-var-register:
21325     # v->register = "ecx"
21326     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
21327     (copy-array Heap "ecx" %eax)
21328 $test-add-literal-to-reg:initialize-literal-type:
21329     # var type/edx: (payload type-tree) = literal
21330     68/push 0/imm32/right:null
21331     68/push 0/imm32/right:null
21332     68/push 0/imm32/left:unused
21333     68/push 0/imm32/value:literal
21334     68/push 1/imm32/is-atom?:true
21335     68/push 0x11/imm32/alloc-id:fake:payload
21336     89/<- %edx 4/r32/esp
21337 $test-add-literal-to-reg:initialize-literal:
21338     # var l/edx: (payload var)
21339     68/push 0/imm32/register
21340     68/push 0/imm32/register
21341     68/push 0/imm32/no-stack-offset
21342     68/push 1/imm32/block-depth
21343     52/push-edx
21344     68/push 0x11/imm32/alloc-id:fake
21345     68/push 0/imm32/name
21346     68/push 0/imm32/name
21347     68/push 0x11/imm32/alloc-id:fake:payload
21348     89/<- %edx 4/r32/esp
21349 $test-add-literal-to-reg:initialize-literal-value:
21350     # l->name = "0x34"
21351     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21352     (copy-array Heap "0x34" %eax)
21353 $test-add-literal-to-reg:initialize-inouts:
21354     # var inouts/esi: (payload stmt-var) = [l]
21355     68/push 0/imm32/is-deref:false
21356     68/push 0/imm32/next
21357     68/push 0/imm32/next
21358     52/push-edx/l
21359     68/push 0x11/imm32/alloc-id:fake
21360     68/push 0x11/imm32/alloc-id:fake:payload
21361     89/<- %esi 4/r32/esp
21362 $test-add-literal-to-reg:initialize-outputs:
21363     # var outputs/edi: (payload stmt-var) = [v]
21364     68/push 0/imm32/is-deref:false
21365     68/push 0/imm32/next
21366     68/push 0/imm32/next
21367     51/push-ecx/v
21368     68/push 0x11/imm32/alloc-id:fake
21369     68/push 0x11/imm32/alloc-id:fake:payload
21370     89/<- %edi 4/r32/esp
21371 $test-add-literal-to-reg:initialize-stmt:
21372     # var stmt/esi: (addr statement)
21373     68/push 0/imm32/next
21374     68/push 0/imm32/next
21375     57/push-edi/outputs
21376     68/push 0x11/imm32/alloc-id:fake
21377     56/push-esi/inouts
21378     68/push 0x11/imm32/alloc-id:fake
21379     68/push 0/imm32/operation
21380     68/push 0/imm32/operation
21381     68/push 1/imm32/tag:stmt1
21382     89/<- %esi 4/r32/esp
21383 $test-add-literal-to-reg:initialize-stmt-operation:
21384     # stmt->operation = "add"
21385     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21386     (copy-array Heap "add" %eax)
21387     # convert
21388     c7 0/subop/copy *Curr-block-depth 0/imm32
21389     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21390     (flush _test-output-buffered-file)
21391 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21397     # check output
21398     (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg")
21399     # . epilogue
21400     89/<- %esp 5/r32/ebp
21401     5d/pop-to-ebp
21402     c3/return
21403 
21404 test-add-literal-to-mem:
21405     #   add-to var1, 0x34
21406     # =>
21407     #   81 0/subop/add %eax 0x34/imm32
21408     #
21409     # . prologue
21410     55/push-ebp
21411     89/<- %ebp 4/r32/esp
21412     # setup
21413     (clear-stream _test-output-stream)
21414     (clear-stream $_test-output-buffered-file->buffer)
21415 $test-add-literal-to-mem:initialize-type:
21416     # var type/ecx: (payload type-tree) = int
21417     68/push 0/imm32/right:null
21418     68/push 0/imm32/right:null
21419     68/push 0/imm32/left:unused
21420     68/push 1/imm32/value:int
21421     68/push 1/imm32/is-atom?:true
21422     68/push 0x11/imm32/alloc-id:fake:payload
21423     89/<- %ecx 4/r32/esp
21424 $test-add-literal-to-mem:initialize-var1:
21425     # var var1/ecx: (payload var)
21426     68/push 0/imm32/register
21427     68/push 0/imm32/register
21428     68/push 8/imm32/stack-offset
21429     68/push 1/imm32/block-depth
21430     51/push-ecx
21431     68/push 0x11/imm32/alloc-id:fake
21432     68/push 0/imm32/name
21433     68/push 0/imm32/name
21434     68/push 0x11/imm32/alloc-id:fake:payload
21435     89/<- %ecx 4/r32/esp
21436 $test-add-literal-to-mem:initialize-var1-name:
21437     # var1->name = "var1"
21438     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21439     (copy-array Heap "var1" %eax)
21440 $test-add-literal-to-mem:initialize-literal-type:
21441     # var type/edx: (payload type-tree) = literal
21442     68/push 0/imm32/right:null
21443     68/push 0/imm32/right:null
21444     68/push 0/imm32/left:unused
21445     68/push 0/imm32/value:literal
21446     68/push 1/imm32/is-atom?:true
21447     68/push 0x11/imm32/alloc-id:fake:payload
21448     89/<- %edx 4/r32/esp
21449 $test-add-literal-to-mem:initialize-literal:
21450     # var l/edx: (payload var)
21451     68/push 0/imm32/register
21452     68/push 0/imm32/register
21453     68/push 0/imm32/no-stack-offset
21454     68/push 1/imm32/block-depth
21455     52/push-edx
21456     68/push 0x11/imm32/alloc-id:fake
21457     68/push 0/imm32/name
21458     68/push 0/imm32/name
21459     68/push 0x11/imm32/alloc-id:fake:payload
21460     89/<- %edx 4/r32/esp
21461 $test-add-literal-to-mem:initialize-literal-value:
21462     # l->name = "0x34"
21463     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21464     (copy-array Heap "0x34" %eax)
21465 $test-add-literal-to-mem:initialize-inouts:
21466     # var inouts/esi: (payload stmt-var) = [l]
21467     68/push 0/imm32/is-deref:false
21468     68/push 0/imm32/next
21469     68/push 0/imm32/next
21470     52/push-edx/l
21471     68/push 0x11/imm32/alloc-id:fake
21472     68/push 0x11/imm32/alloc-id:fake:payload
21473     89/<- %esi 4/r32/esp
21474     # var inouts = (handle stmt-var) = [var1, var2]
21475     68/push 0/imm32/is-deref:false
21476     56/push-esi/next
21477     68/push 0x11/imm32/alloc-id:fake
21478     51/push-ecx/var1
21479     68/push 0x11/imm32/alloc-id:fake
21480     68/push 0x11/imm32/alloc-id:fake:payload
21481     89/<- %esi 4/r32/esp
21482 $test-add-literal-to-mem:initialize-stmt:
21483     # var stmt/esi: (addr statement)
21484     68/push 0/imm32/next
21485     68/push 0/imm32/next
21486     68/push 0/imm32/outputs
21487     68/push 0/imm32/outputs
21488     56/push-esi/inouts
21489     68/push 0x11/imm32/alloc-id:fake
21490     68/push 0/imm32/operation
21491     68/push 0/imm32/operation
21492     68/push 1/imm32/tag:stmt1
21493     89/<- %esi 4/r32/esp
21494 $test-add-literal-to-mem:initialize-stmt-operation:
21495     # stmt->operation = "add-to"
21496     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21497     (copy-array Heap "add-to" %eax)
21498     # convert
21499     c7 0/subop/copy *Curr-block-depth 0/imm32
21500     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21501     (flush _test-output-buffered-file)
21502 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21508     # check output
21509     (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem")
21510     # . epilogue
21511     89/<- %esp 5/r32/ebp
21512     5d/pop-to-ebp
21513     c3/return
21514 
21515 test-shift-reg-by-literal:
21516     #   var1/ecx <- shift-left 2
21517     # =>
21518     #   c1/shift 4/subop/left %ecx 2/imm8
21519     #
21520     # . prologue
21521     55/push-ebp
21522     89/<- %ebp 4/r32/esp
21523     # setup
21524     (clear-stream _test-output-stream)
21525     (clear-stream $_test-output-buffered-file->buffer)
21526 $test-shift-reg-by-literal:initialize-var-type:
21527     # var type/ecx: (payload type-tree) = int
21528     68/push 0/imm32/right:null
21529     68/push 0/imm32/right:null
21530     68/push 0/imm32/left:unused
21531     68/push 1/imm32/value:int
21532     68/push 1/imm32/is-atom?:true
21533     68/push 0x11/imm32/alloc-id:fake:payload
21534     89/<- %ecx 4/r32/esp
21535 $test-shift-reg-by-literal:initialize-var:
21536     # var v/ecx: (payload var)
21537     68/push 0/imm32/register
21538     68/push 0/imm32/register
21539     68/push 0/imm32/no-stack-offset
21540     68/push 1/imm32/block-depth
21541     51/push-ecx
21542     68/push 0x11/imm32/alloc-id:fake
21543     68/push 0/imm32/name
21544     68/push 0/imm32/name
21545     68/push 0x11/imm32/alloc-id:fake:payload
21546     89/<- %ecx 4/r32/esp
21547 $test-shift-reg-by-literal:initialize-var-name:
21548     # v->name = "v"
21549     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21550     (copy-array Heap "v" %eax)
21551 $test-shift-reg-by-literal:initialize-var-register:
21552     # v->register = "ecx"
21553     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
21554     (copy-array Heap "ecx" %eax)
21555 $test-shift-reg-by-literal:initialize-literal-type:
21556     # var type/edx: (payload type-tree) = literal
21557     68/push 0/imm32/right:null
21558     68/push 0/imm32/right:null
21559     68/push 0/imm32/left:unused
21560     68/push 0/imm32/value:literal
21561     68/push 1/imm32/is-atom?:true
21562     68/push 0x11/imm32/alloc-id:fake:payload
21563     89/<- %edx 4/r32/esp
21564 $test-shift-reg-by-literal:initialize-literal:
21565     # var l/edx: (payload var)
21566     68/push 0/imm32/register
21567     68/push 0/imm32/register
21568     68/push 0/imm32/no-stack-offset
21569     68/push 1/imm32/block-depth
21570     52/push-edx
21571     68/push 0x11/imm32/alloc-id:fake
21572     68/push 0/imm32/name
21573     68/push 0/imm32/name
21574     68/push 0x11/imm32/alloc-id:fake:payload
21575     89/<- %edx 4/r32/esp
21576 $test-shift-reg-by-literal:initialize-literal-value:
21577     # l->name = "2"
21578     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21579     (copy-array Heap "2" %eax)
21580 $test-shift-reg-by-literal:initialize-inouts:
21581     # var inouts/esi: (payload stmt-var) = [l]
21582     68/push 0/imm32/is-deref:false
21583     68/push 0/imm32/next
21584     68/push 0/imm32/next
21585     52/push-edx/l
21586     68/push 0x11/imm32/alloc-id:fake
21587     68/push 0x11/imm32/alloc-id:fake:payload
21588     89/<- %esi 4/r32/esp
21589 $test-shift-reg-by-literal:initialize-outputs:
21590     # var outputs/edi: (payload stmt-var) = [v]
21591     68/push 0/imm32/is-deref:false
21592     68/push 0/imm32/next
21593     68/push 0/imm32/next
21594     51/push-ecx/v
21595     68/push 0x11/imm32/alloc-id:fake
21596     68/push 0x11/imm32/alloc-id:fake:payload
21597     89/<- %edi 4/r32/esp
21598 $test-shift-reg-by-literal:initialize-stmt:
21599     # var stmt/esi: (addr statement)
21600     68/push 0/imm32/next
21601     68/push 0/imm32/next
21602     57/push-edi/outputs
21603     68/push 0x11/imm32/alloc-id:fake
21604     56/push-esi/inouts
21605     68/push 0x11/imm32/alloc-id:fake
21606     68/push 0/imm32/operation
21607     68/push 0/imm32/operation
21608     68/push 1/imm32/tag:stmt1
21609     89/<- %esi 4/r32/esp
21610 $test-shift-reg-by-literal:initialize-stmt-operation:
21611     # stmt->operation = "shift-left"
21612     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21613     (copy-array Heap "shift-left" %eax)
21614     # convert
21615     c7 0/subop/copy *Curr-block-depth 0/imm32
21616     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21617     (flush _test-output-buffered-file)
21618 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21624     # check output
21625     (check-next-stream-line-equal _test-output-stream "c1/shift 4/subop/left %ecx 2/imm8" "F - test-shift-reg-by-literal")
21626     # . epilogue
21627     89/<- %esp 5/r32/ebp
21628     5d/pop-to-ebp
21629     c3/return
21630 
21631 test-shift-mem-by-literal:
21632     #   shift-left var 3
21633     # =>
21634     #   c1/shift 4/subop/left *(ebp+8) 3/imm8
21635     #
21636     # . prologue
21637     55/push-ebp
21638     89/<- %ebp 4/r32/esp
21639     # setup
21640     (clear-stream _test-output-stream)
21641     (clear-stream $_test-output-buffered-file->buffer)
21642 $test-shift-mem-by-literal:initialize-type:
21643     # var type/ecx: (payload type-tree) = int
21644     68/push 0/imm32/right:null
21645     68/push 0/imm32/right:null
21646     68/push 0/imm32/left:unused
21647     68/push 1/imm32/value:int
21648     68/push 1/imm32/is-atom?:true
21649     68/push 0x11/imm32/alloc-id:fake:payload
21650     89/<- %ecx 4/r32/esp
21651 $test-shift-mem-by-literal:initialize-var1:
21652     # var var1/ecx: (payload var)
21653     68/push 0/imm32/register
21654     68/push 0/imm32/register
21655     68/push 8/imm32/stack-offset
21656     68/push 1/imm32/block-depth
21657     51/push-ecx
21658     68/push 0x11/imm32/alloc-id:fake
21659     68/push 0/imm32/name
21660     68/push 0/imm32/name
21661     68/push 0x11/imm32/alloc-id:fake:payload
21662     89/<- %ecx 4/r32/esp
21663 $test-shift-mem-by-literal:initialize-var1-name:
21664     # var1->name = "var1"
21665     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21666     (copy-array Heap "var1" %eax)
21667 $test-shift-mem-by-literal:initialize-literal-type:
21668     # var type/edx: (payload type-tree) = literal
21669     68/push 0/imm32/right:null
21670     68/push 0/imm32/right:null
21671     68/push 0/imm32/left:unused
21672     68/push 0/imm32/value:literal
21673     68/push 1/imm32/is-atom?:true
21674     68/push 0x11/imm32/alloc-id:fake:payload
21675     89/<- %edx 4/r32/esp
21676 $test-shift-mem-by-literal:initialize-literal:
21677     # var l/edx: (payload var)
21678     68/push 0/imm32/register
21679     68/push 0/imm32/register
21680     68/push 0/imm32/no-stack-offset
21681     68/push 1/imm32/block-depth
21682     52/push-edx
21683     68/push 0x11/imm32/alloc-id:fake
21684     68/push 0/imm32/name
21685     68/push 0/imm32/name
21686     68/push 0x11/imm32/alloc-id:fake:payload
21687     89/<- %edx 4/r32/esp
21688 $test-shift-mem-by-literal:initialize-literal-value:
21689     # l->name = "3"
21690     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21691     (copy-array Heap "3" %eax)
21692 $test-shift-mem-by-literal:initialize-inouts:
21693     # var inouts/esi: (payload stmt-var) = [l]
21694     68/push 0/imm32/is-deref:false
21695     68/push 0/imm32/next
21696     68/push 0/imm32/next
21697     52/push-edx/l
21698     68/push 0x11/imm32/alloc-id:fake
21699     68/push 0x11/imm32/alloc-id:fake:payload
21700     89/<- %esi 4/r32/esp
21701     # var inouts = (handle stmt-var) = [var1, var2]
21702     68/push 0/imm32/is-deref:false
21703     56/push-esi/next
21704     68/push 0x11/imm32/alloc-id:fake
21705     51/push-ecx/var1
21706     68/push 0x11/imm32/alloc-id:fake
21707     68/push 0x11/imm32/alloc-id:fake:payload
21708     89/<- %esi 4/r32/esp
21709 $test-shift-mem-by-literal:initialize-stmt:
21710     # var stmt/esi: (addr statement)
21711     68/push 0/imm32/next
21712     68/push 0/imm32/next
21713     68/push 0/imm32/outputs
21714     68/push 0/imm32/outputs
21715     56/push-esi/inouts
21716     68/push 0x11/imm32/alloc-id:fake
21717     68/push 0/imm32/operation
21718     68/push 0/imm32/operation
21719     68/push 1/imm32/tag:stmt1
21720     89/<- %esi 4/r32/esp
21721 $test-shift-mem-by-literal:initialize-stmt-operation:
21722     # stmt->operation = "shift-left"
21723     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21724     (copy-array Heap "shift-left" %eax)
21725     # convert
21726     c7 0/subop/copy *Curr-block-depth 0/imm32
21727     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21728     (flush _test-output-buffered-file)
21729 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21735     # check output
21736     (check-next-stream-line-equal _test-output-stream "c1/shift 4/subop/left *(ebp+0x00000008) 3/imm8" "F - test-shift-mem-by-literal")
21737     # . epilogue
21738     89/<- %esp 5/r32/ebp
21739     5d/pop-to-ebp
21740     c3/return
21741 
21742 test-compare-reg-with-reg:
21743     #   compare var1/ecx, var2/eax
21744     # =>
21745     #   39/compare %ecx 0/r32/eax
21746     #
21747     # . prologue
21748     55/push-ebp
21749     89/<- %ebp 4/r32/esp
21750     # setup
21751     (clear-stream _test-output-stream)
21752     (clear-stream $_test-output-buffered-file->buffer)
21753 $test-compare-reg-with-reg:initialize-type:
21754     # var type/ecx: (payload type-tree) = int
21755     68/push 0/imm32/right:null
21756     68/push 0/imm32/right:null
21757     68/push 0/imm32/left:unused
21758     68/push 1/imm32/value:int
21759     68/push 1/imm32/is-atom?:true
21760     68/push 0x11/imm32/alloc-id:fake:payload
21761     89/<- %ecx 4/r32/esp
21762 $test-compare-reg-with-reg:initialize-var1:
21763     # var var1/ecx: (payload var)
21764     68/push 0/imm32/register
21765     68/push 0/imm32/register
21766     68/push 0/imm32/no-stack-offset
21767     68/push 1/imm32/block-depth
21768     51/push-ecx
21769     68/push 0x11/imm32/alloc-id:fake
21770     68/push 0/imm32/name
21771     68/push 0/imm32/name
21772     68/push 0x11/imm32/alloc-id:fake:payload
21773     89/<- %ecx 4/r32/esp
21774 $test-compare-reg-with-reg:initialize-var1-name:
21775     # var1->name = "var1"
21776     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21777     (copy-array Heap "var1" %eax)
21778 $test-compare-reg-with-reg:initialize-var1-register:
21779     # var1->register = "ecx"
21780     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
21781     (copy-array Heap "ecx" %eax)
21782 $test-compare-reg-with-reg:initialize-var2:
21783     # var var2/edx: (payload var)
21784     68/push 0/imm32/register
21785     68/push 0/imm32/register
21786     68/push 0/imm32/no-stack-offset
21787     68/push 1/imm32/block-depth
21788     ff 6/subop/push *(ecx+0x10)
21789     68/push 0x11/imm32/alloc-id:fake
21790     68/push 0/imm32/name
21791     68/push 0/imm32/name
21792     68/push 0x11/imm32/alloc-id:fake:payload
21793     89/<- %edx 4/r32/esp
21794 $test-compare-reg-with-reg:initialize-var2-name:
21795     # var2->name = "var2"
21796     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21797     (copy-array Heap "var2" %eax)
21798 $test-compare-reg-with-reg:initialize-var2-register:
21799     # var2->register = "eax"
21800     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
21801     (copy-array Heap "eax" %eax)
21802 $test-compare-reg-with-reg:initialize-inouts:
21803     # var inouts/esi: (payload stmt-var) = [var2]
21804     68/push 0/imm32/is-deref:false
21805     68/push 0/imm32/next
21806     68/push 0/imm32/next
21807     52/push-edx/var2
21808     68/push 0x11/imm32/alloc-id:fake
21809     68/push 0x11/imm32/alloc-id:fake:payload
21810     89/<- %esi 4/r32/esp
21811     # inouts = [var1, var2]
21812     68/push 0/imm32/is-deref:false
21813     56/push-esi/next
21814     68/push 0x11/imm32/alloc-id:fake
21815     51/push-ecx/var1
21816     68/push 0x11/imm32/alloc-id:fake
21817     68/push 0x11/imm32/alloc-id:fake:payload
21818     89/<- %esi 4/r32/esp
21819 $test-compare-reg-with-reg:initialize-stmt:
21820     # var stmt/esi: (addr statement)
21821     68/push 0/imm32/next
21822     68/push 0/imm32/next
21823     68/push 0/imm32/outputs
21824     68/push 0/imm32/outputs
21825     56/push-esi/inouts
21826     68/push 0x11/imm32/alloc-id:fake
21827     68/push 0/imm32/operation
21828     68/push 0/imm32/operation
21829     68/push 1/imm32/tag:stmt1
21830     89/<- %esi 4/r32/esp
21831 $test-compare-reg-with-reg:initialize-stmt-operation:
21832     # stmt->operation = "compare"
21833     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21834     (copy-array Heap "compare" %eax)
21835     # convert
21836     c7 0/subop/copy *Curr-block-depth 0/imm32
21837     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21838     (flush _test-output-buffered-file)
21839 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21845     # check output
21846     (check-next-stream-line-equal _test-output-stream "39/compare-> %ecx 0x00000000/r32" "F - test-compare-reg-with-reg")
21847     # . epilogue
21848     89/<- %esp 5/r32/ebp
21849     5d/pop-to-ebp
21850     c3/return
21851 
21852 test-compare-mem-with-reg:
21853     #   compare var1, var2/eax
21854     # =>
21855     #   39/compare *(ebp+___) 0/r32/eax
21856     #
21857     # . prologue
21858     55/push-ebp
21859     89/<- %ebp 4/r32/esp
21860     # setup
21861     (clear-stream _test-output-stream)
21862     (clear-stream $_test-output-buffered-file->buffer)
21863 $test-compare-mem-with-reg:initialize-type:
21864     # var type/ecx: (payload type-tree) = int
21865     68/push 0/imm32/right:null
21866     68/push 0/imm32/right:null
21867     68/push 0/imm32/left:unused
21868     68/push 1/imm32/value:int
21869     68/push 1/imm32/is-atom?:true
21870     68/push 0x11/imm32/alloc-id:fake:payload
21871     89/<- %ecx 4/r32/esp
21872 $test-compare-mem-with-reg:initialize-var1:
21873     # var var1/ecx: (payload var)
21874     68/push 0/imm32/register
21875     68/push 0/imm32/register
21876     68/push 8/imm32/stack-offset
21877     68/push 1/imm32/block-depth
21878     51/push-ecx
21879     68/push 0x11/imm32/alloc-id:fake
21880     68/push 0/imm32/name
21881     68/push 0/imm32/name
21882     68/push 0x11/imm32/alloc-id:fake:payload
21883     89/<- %ecx 4/r32/esp
21884 $test-compare-mem-with-reg:initialize-var1-name:
21885     # var1->name = "var1"
21886     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21887     (copy-array Heap "var1" %eax)
21888 $test-compare-mem-with-reg:initialize-var2:
21889     # var var2/edx: (payload var)
21890     68/push 0/imm32/register
21891     68/push 0/imm32/register
21892     68/push 0/imm32/no-stack-offset
21893     68/push 1/imm32/block-depth
21894     ff 6/subop/push *(ecx+0x10)
21895     68/push 0x11/imm32/alloc-id:fake
21896     68/push 0/imm32/name
21897     68/push 0/imm32/name
21898     68/push 0x11/imm32/alloc-id:fake:payload
21899     89/<- %edx 4/r32/esp
21900 $test-compare-mem-with-reg:initialize-var2-name:
21901     # var2->name = "var2"
21902     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
21903     (copy-array Heap "var2" %eax)
21904 $test-compare-mem-with-reg:initialize-var2-register:
21905     # var2->register = "eax"
21906     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
21907     (copy-array Heap "eax" %eax)
21908 $test-compare-mem-with-reg:initialize-inouts:
21909     # var inouts/esi: (payload stmt-var) = [var2]
21910     68/push 0/imm32/is-deref:false
21911     68/push 0/imm32/next
21912     68/push 0/imm32/next
21913     52/push-edx/var2
21914     68/push 0x11/imm32/alloc-id:fake
21915     68/push 0x11/imm32/alloc-id:fake:payload
21916     89/<- %esi 4/r32/esp
21917     # inouts = [var1, var2]
21918     68/push 0/imm32/is-deref:false
21919     56/push-esi/next
21920     68/push 0x11/imm32/alloc-id:fake
21921     51/push-ecx/var1
21922     68/push 0x11/imm32/alloc-id:fake
21923     68/push 0x11/imm32/alloc-id:fake:payload
21924     89/<- %esi 4/r32/esp
21925 $test-compare-mem-with-reg:initialize-stmt:
21926     # var stmt/esi: (addr statement)
21927     68/push 0/imm32/next
21928     68/push 0/imm32/next
21929     68/push 0/imm32/outputs
21930     68/push 0/imm32/outputs
21931     56/push-esi/inouts
21932     68/push 0x11/imm32/alloc-id:fake
21933     68/push 0/imm32/operation
21934     68/push 0/imm32/operation
21935     68/push 1/imm32/tag:stmt1
21936     89/<- %esi 4/r32/esp
21937 $test-compare-mem-with-reg:initialize-stmt-operation:
21938     # stmt->operation = "compare"
21939     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21940     (copy-array Heap "compare" %eax)
21941     # convert
21942     c7 0/subop/copy *Curr-block-depth 0/imm32
21943     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
21944     (flush _test-output-buffered-file)
21945 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21951     # check output
21952     (check-next-stream-line-equal _test-output-stream "39/compare-> *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-mem-with-reg")
21953     # . epilogue
21954     89/<- %esp 5/r32/ebp
21955     5d/pop-to-ebp
21956     c3/return
21957 
21958 test-compare-reg-with-mem:
21959     #   compare var1/eax, var2
21960     # =>
21961     #   3b/compare<- *(ebp+___) 0/r32/eax
21962     #
21963     # . prologue
21964     55/push-ebp
21965     89/<- %ebp 4/r32/esp
21966     # setup
21967     (clear-stream _test-output-stream)
21968     (clear-stream $_test-output-buffered-file->buffer)
21969 $test-compare-reg-with-mem:initialize-type:
21970     # var type/ecx: (payload type-tree) = int
21971     68/push 0/imm32/right:null
21972     68/push 0/imm32/right:null
21973     68/push 0/imm32/left:unused
21974     68/push 1/imm32/value:int
21975     68/push 1/imm32/is-atom?:true
21976     68/push 0x11/imm32/alloc-id:fake:payload
21977     89/<- %ecx 4/r32/esp
21978 $test-compare-reg-with-mem:initialize-var1:
21979     # var var1/ecx: (payload var)
21980     68/push 0/imm32/register
21981     68/push 0/imm32/register
21982     68/push 0/imm32/no-stack-offset
21983     68/push 1/imm32/block-depth
21984     51/push-ecx
21985     68/push 0x11/imm32/alloc-id:fake
21986     68/push 0/imm32/name
21987     68/push 0/imm32/name
21988     68/push 0x11/imm32/alloc-id:fake:payload
21989     89/<- %ecx 4/r32/esp
21990 $test-compare-reg-with-mem:initialize-var1-name:
21991     # var1->name = "var1"
21992     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21993     (copy-array Heap "var1" %eax)
21994 $test-compare-reg-with-mem:initialize-var1-register:
21995     # var1->register = "eax"
21996     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
21997     (copy-array Heap "eax" %eax)
21998 $test-compare-reg-with-mem:initialize-var2:
21999     # var var2/edx: (payload var)
22000     68/push 0/imm32/register
22001     68/push 0/imm32/register
22002     68/push 8/imm32/stack-offset
22003     68/push 1/imm32/block-depth
22004     ff 6/subop/push *(ecx+0x10)
22005     68/push 0x11/imm32/alloc-id:fake
22006     68/push 0/imm32/name
22007     68/push 0/imm32/name
22008     68/push 0x11/imm32/alloc-id:fake:payload
22009     89/<- %edx 4/r32/esp
22010 $test-compare-reg-with-mem:initialize-var2-name:
22011     # var2->name = "var2"
22012     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
22013     (copy-array Heap "var2" %eax)
22014 $test-compare-reg-with-mem:initialize-inouts:
22015     # var inouts/esi: (payload stmt-var) = [var2]
22016     68/push 0/imm32/is-deref:false
22017     68/push 0/imm32/next
22018     68/push 0/imm32/next
22019     52/push-edx/var2
22020     68/push 0x11/imm32/alloc-id:fake
22021     68/push 0x11/imm32/alloc-id:fake:payload
22022     89/<- %esi 4/r32/esp
22023     # inouts = [var1, var2]
22024     68/push 0/imm32/is-deref:false
22025     56/push-esi/next
22026     68/push 0x11/imm32/alloc-id:fake
22027     51/push-ecx/var1
22028     68/push 0x11/imm32/alloc-id:fake
22029     68/push 0x11/imm32/alloc-id:fake:payload
22030     89/<- %esi 4/r32/esp
22031 $test-compare-reg-with-mem:initialize-stmt:
22032     # var stmt/esi: (addr statement)
22033     68/push 0/imm32/next
22034     68/push 0/imm32/next
22035     68/push 0/imm32/outputs
22036     68/push 0/imm32/outputs
22037     56/push-esi/inouts
22038     68/push 0x11/imm32/alloc-id:fake
22039     68/push 0/imm32/operation
22040     68/push 0/imm32/operation
22041     68/push 1/imm32/tag:stmt1
22042     89/<- %esi 4/r32/esp
22043 $test-compare-reg-with-mem:initialize-stmt-operation:
22044     # stmt->operation = "compare"
22045     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22046     (copy-array Heap "compare" %eax)
22047     # convert
22048     c7 0/subop/copy *Curr-block-depth 0/imm32
22049     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22050     (flush _test-output-buffered-file)
22051 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
22057     # check output
22058     (check-next-stream-line-equal _test-output-stream "3b/compare<- *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-reg-with-mem")
22059     # . epilogue
22060     89/<- %esp 5/r32/ebp
22061     5d/pop-to-ebp
22062     c3/return
22063 
22064 test-compare-mem-with-literal:
22065     #   compare var1, 0x34
22066     # =>
22067     #   81 7/subop/compare *(ebp+___) 0x34/imm32
22068     #
22069     # . prologue
22070     55/push-ebp
22071     89/<- %ebp 4/r32/esp
22072     # setup
22073     (clear-stream _test-output-stream)
22074     (clear-stream $_test-output-buffered-file->buffer)
22075 $test-compare-mem-with-literal:initialize-type:
22076     # var type/ecx: (payload type-tree) = int
22077     68/push 0/imm32/right:null
22078     68/push 0/imm32/right:null
22079     68/push 0/imm32/left:unused
22080     68/push 1/imm32/value:int
22081     68/push 1/imm32/is-atom?:true
22082     68/push 0x11/imm32/alloc-id:fake:payload
22083     89/<- %ecx 4/r32/esp
22084 $test-compare-mem-with-literal:initialize-var1:
22085     # var var1/ecx: (payload var)
22086     68/push 0/imm32/register
22087     68/push 0/imm32/register
22088     68/push 8/imm32/stack-offset
22089     68/push 1/imm32/block-depth
22090     51/push-ecx
22091     68/push 0x11/imm32/alloc-id:fake
22092     68/push 0/imm32/name
22093     68/push 0/imm32/name
22094     68/push 0x11/imm32/alloc-id:fake:payload
22095     89/<- %ecx 4/r32/esp
22096 $test-compare-mem-with-literal:initialize-var1-name:
22097     # var1->name = "var1"
22098     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22099     (copy-array Heap "var1" %eax)
22100 $test-compare-mem-with-literal:initialize-literal-type:
22101     # var type/edx: (payload type-tree) = literal
22102     68/push 0/imm32/right:null
22103     68/push 0/imm32/right:null
22104     68/push 0/imm32/left:unused
22105     68/push 0/imm32/value:literal
22106     68/push 1/imm32/is-atom?:true
22107     68/push 0x11/imm32/alloc-id:fake:payload
22108     89/<- %edx 4/r32/esp
22109 $test-compare-mem-with-literal:initialize-literal:
22110     # var l/edx: (payload var)
22111     68/push 0/imm32/register
22112     68/push 0/imm32/register
22113     68/push 0/imm32/no-stack-offset
22114     68/push 1/imm32/block-depth
22115     52/push-edx
22116     68/push 0x11/imm32/alloc-id:fake
22117     68/push 0/imm32/name
22118     68/push 0/imm32/name
22119     68/push 0x11/imm32/alloc-id:fake:payload
22120     89/<- %edx 4/r32/esp
22121 $test-compare-mem-with-literal:initialize-literal-value:
22122     # l->name = "0x34"
22123     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
22124     (copy-array Heap "0x34" %eax)
22125 $test-compare-mem-with-literal:initialize-inouts:
22126     # var inouts/esi: (payload stmt-var) = [l]
22127     68/push 0/imm32/is-deref:false
22128     68/push 0/imm32/next
22129     68/push 0/imm32/next
22130     52/push-edx/l
22131     68/push 0x11/imm32/alloc-id:fake
22132     68/push 0x11/imm32/alloc-id:fake:payload
22133     89/<- %esi 4/r32/esp
22134     # var inouts = (handle stmt-var) = [var1, var2]
22135     68/push 0/imm32/is-deref:false
22136     56/push-esi/next
22137     68/push 0x11/imm32/alloc-id:fake
22138     51/push-ecx/var1
22139     68/push 0x11/imm32/alloc-id:fake
22140     68/push 0x11/imm32/alloc-id:fake:payload
22141     89/<- %esi 4/r32/esp
22142 $test-compare-mem-with-literal:initialize-stmt:
22143     # var stmt/esi: (addr statement)
22144     68/push 0/imm32/next
22145     68/push 0/imm32/next
22146     68/push 0/imm32/outputs
22147     68/push 0/imm32/outputs
22148     56/push-esi/inouts
22149     68/push 0x11/imm32/alloc-id:fake
22150     68/push 0/imm32/operation
22151     68/push 0/imm32/operation
22152     68/push 1/imm32/tag:stmt1
22153     89/<- %esi 4/r32/esp
22154 $test-compare-mem-with-literal:initialize-stmt-operation:
22155     # stmt->operation = "compare"
22156     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22157     (copy-array Heap "compare" %eax)
22158     # convert
22159     c7 0/subop/copy *Curr-block-depth 0/imm32
22160     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22161     (flush _test-output-buffered-file)
22162 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
22168     # check output
22169     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare *(ebp+0x00000008) 0x34/imm32" "F - test-compare-mem-with-literal")
22170     # . epilogue
22171     89/<- %esp 5/r32/ebp
22172     5d/pop-to-ebp
22173     c3/return
22174 
22175 test-compare-eax-with-literal:
22176     #   compare var1/eax 0x34
22177     # =>
22178     #   3d/compare-eax-with 0x34/imm32
22179     #
22180     # . prologue
22181     55/push-ebp
22182     89/<- %ebp 4/r32/esp
22183     # setup
22184     (clear-stream _test-output-stream)
22185     (clear-stream $_test-output-buffered-file->buffer)
22186 $test-compare-eax-with-literal:initialize-type:
22187     # var type/ecx: (payload type-tree) = int
22188     68/push 0/imm32/right:null
22189     68/push 0/imm32/right:null
22190     68/push 0/imm32/left:unused
22191     68/push 1/imm32/value:int
22192     68/push 1/imm32/is-atom?:true
22193     68/push 0x11/imm32/alloc-id:fake:payload
22194     89/<- %ecx 4/r32/esp
22195 $test-compare-eax-with-literal:initialize-var1:
22196     # var var1/ecx: (payload var)
22197     68/push 0/imm32/register
22198     68/push 0/imm32/register
22199     68/push 0/imm32/no-stack-offset
22200     68/push 1/imm32/block-depth
22201     51/push-ecx
22202     68/push 0x11/imm32/alloc-id:fake
22203     68/push 0/imm32/name
22204     68/push 0/imm32/name
22205     68/push 0x11/imm32/alloc-id:fake:payload
22206     89/<- %ecx 4/r32/esp
22207 $test-compare-eax-with-literal:initialize-var1-name:
22208     # var1->name = "var1"
22209     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22210     (copy-array Heap "var1" %eax)
22211 $test-compare-eax-with-literal:initialize-var1-register:
22212     # v->register = "eax"
22213     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
22214     (copy-array Heap "eax" %eax)
22215 $test-compare-eax-with-literal:initialize-literal-type:
22216     # var type/edx: (payload type-tree) = literal
22217     68/push 0/imm32/right:null
22218     68/push 0/imm32/right:null
22219     68/push 0/imm32/left:unused
22220     68/push 0/imm32/value:literal
22221     68/push 1/imm32/is-atom?:true
22222     68/push 0x11/imm32/alloc-id:fake:payload
22223     89/<- %edx 4/r32/esp
22224 $test-compare-eax-with-literal:initialize-literal:
22225     # var l/edx: (payload var)
22226     68/push 0/imm32/register
22227     68/push 0/imm32/register
22228     68/push 0/imm32/no-stack-offset
22229     68/push 1/imm32/block-depth
22230     52/push-edx
22231     68/push 0x11/imm32/alloc-id:fake
22232     68/push 0/imm32/name
22233     68/push 0/imm32/name
22234     68/push 0x11/imm32/alloc-id:fake:payload
22235     89/<- %edx 4/r32/esp
22236 $test-compare-eax-with-literal:initialize-literal-value:
22237     # l->name = "0x34"
22238     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
22239     (copy-array Heap "0x34" %eax)
22240 $test-compare-eax-with-literal:initialize-inouts:
22241     # var inouts/esi: (payload stmt-var) = [l]
22242     68/push 0/imm32/is-deref:false
22243     68/push 0/imm32/next
22244     68/push 0/imm32/next
22245     52/push-edx/l
22246     68/push 0x11/imm32/alloc-id:fake
22247     68/push 0x11/imm32/alloc-id:fake:payload
22248     89/<- %esi 4/r32/esp
22249     # var inouts = (handle stmt-var) = [var1, var2]
22250     68/push 0/imm32/is-deref:false
22251     56/push-esi/next
22252     68/push 0x11/imm32/alloc-id:fake
22253     51/push-ecx/var1
22254     68/push 0x11/imm32/alloc-id:fake
22255     68/push 0x11/imm32/alloc-id:fake:payload
22256     89/<- %esi 4/r32/esp
22257 $test-compare-eax-with-literal:initialize-stmt:
22258     # var stmt/esi: (addr statement)
22259     68/push 0/imm32/next
22260     68/push 0/imm32/next
22261     68/push 0/imm32/outputs
22262     68/push 0/imm32/outputs
22263     56/push-esi/inouts
22264     68/push 0x11/imm32/alloc-id:fake
22265     68/push 0/imm32/operation
22266     68/push 0/imm32/operation
22267     68/push 1/imm32/tag:stmt1
22268     89/<- %esi 4/r32/esp
22269 $test-compare-eax-with-literal:initialize-stmt-operation:
22270     # stmt->operation = "compare"
22271     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22272     (copy-array Heap "compare" %eax)
22273     # convert
22274     c7 0/subop/copy *Curr-block-depth 0/imm32
22275     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22276     (flush _test-output-buffered-file)
22277 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
22283     # check output
22284     (check-next-stream-line-equal _test-output-stream "3d/compare-eax-with 0x34/imm32" "F - test-compare-eax-with-literal")
22285     # . epilogue
22286     89/<- %esp 5/r32/ebp
22287     5d/pop-to-ebp
22288     c3/return
22289 
22290 test-compare-reg-with-literal:
22291     #   compare var1/ecx 0x34
22292     # =>
22293     #   81 7/subop/compare %ecx 0x34/imm32
22294     #
22295     # . prologue
22296     55/push-ebp
22297     89/<- %ebp 4/r32/esp
22298     # setup
22299     (clear-stream _test-output-stream)
22300     (clear-stream $_test-output-buffered-file->buffer)
22301 $test-compare-reg-with-literal:initialize-type:
22302     # var type/ecx: (payload type-tree) = int
22303     68/push 0/imm32/right:null
22304     68/push 0/imm32/right:null
22305     68/push 0/imm32/left:unused
22306     68/push 1/imm32/value:int
22307     68/push 1/imm32/is-atom?:true
22308     68/push 0x11/imm32/alloc-id:fake:payload
22309     89/<- %ecx 4/r32/esp
22310 $test-compare-reg-with-literal:initialize-var1:
22311     # var var1/ecx: (payload var)
22312     68/push 0/imm32/register
22313     68/push 0/imm32/register
22314     68/push 0/imm32/no-stack-offset
22315     68/push 1/imm32/block-depth
22316     51/push-ecx
22317     68/push 0x11/imm32/alloc-id:fake
22318     68/push 0/imm32/name
22319     68/push 0/imm32/name
22320     68/push 0x11/imm32/alloc-id:fake:payload
22321     89/<- %ecx 4/r32/esp
22322 $test-compare-reg-with-literal:initialize-var1-name:
22323     # var1->name = "var1"
22324     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22325     (copy-array Heap "var1" %eax)
22326 $test-compare-reg-with-literal:initialize-var1-register:
22327     # v->register = "ecx"
22328     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
22329     (copy-array Heap "ecx" %eax)
22330 $test-compare-reg-with-literal:initialize-literal-type:
22331     # var type/edx: (payload type-tree) = literal
22332     68/push 0/imm32/right:null
22333     68/push 0/imm32/right:null
22334     68/push 0/imm32/left:unused
22335     68/push 0/imm32/value:literal
22336     68/push 1/imm32/is-atom?:true
22337     68/push 0x11/imm32/alloc-id:fake:payload
22338     89/<- %edx 4/r32/esp
22339 $test-compare-reg-with-literal:initialize-literal:
22340     # var l/edx: (payload var)
22341     68/push 0/imm32/register
22342     68/push 0/imm32/register
22343     68/push 0/imm32/no-stack-offset
22344     68/push 1/imm32/block-depth
22345     52/push-edx
22346     68/push 0x11/imm32/alloc-id:fake
22347     68/push 0/imm32/name
22348     68/push 0/imm32/name
22349     68/push 0x11/imm32/alloc-id:fake:payload
22350     89/<- %edx 4/r32/esp
22351 $test-compare-reg-with-literal:initialize-literal-value:
22352     # l->name = "0x34"
22353     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
22354     (copy-array Heap "0x34" %eax)
22355 $test-compare-reg-with-literal:initialize-inouts:
22356     # var inouts/esi: (payload stmt-var) = [l]
22357     68/push 0/imm32/is-deref:false
22358     68/push 0/imm32/next
22359     68/push 0/imm32/next
22360     52/push-edx/l
22361     68/push 0x11/imm32/alloc-id:fake
22362     68/push 0x11/imm32/alloc-id:fake:payload
22363     89/<- %esi 4/r32/esp
22364     # var inouts = (handle stmt-var) = [var1, var2]
22365     68/push 0/imm32/is-deref:false
22366     56/push-esi/next
22367     68/push 0x11/imm32/alloc-id:fake
22368     51/push-ecx/var1
22369     68/push 0x11/imm32/alloc-id:fake
22370     68/push 0x11/imm32/alloc-id:fake:payload
22371     89/<- %esi 4/r32/esp
22372 $test-compare-reg-with-literal:initialize-stmt:
22373     # var stmt/esi: (addr statement)
22374     68/push 0/imm32/next
22375     68/push 0/imm32/next
22376     68/push 0/imm32/outputs
22377     68/push 0/imm32/outputs
22378     56/push-esi/inouts
22379     68/push 0x11/imm32/alloc-id:fake
22380     68/push 0/imm32/operation
22381     68/push 0/imm32/operation
22382     68/push 1/imm32/tag:stmt1
22383     89/<- %esi 4/r32/esp
22384 $test-compare-reg-with-literal:initialize-stmt-operation:
22385     # stmt->operation = "compare"
22386     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22387     (copy-array Heap "compare" %eax)
22388     # convert
22389     c7 0/subop/copy *Curr-block-depth 0/imm32
22390     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22391     (flush _test-output-buffered-file)
22392 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
22398     # check output
22399     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare %ecx 0x34/imm32" "F - test-compare-reg-with-literal")
22400     # . epilogue
22401     89/<- %esp 5/r32/ebp
22402     5d/pop-to-ebp
22403     c3/return
22404 
22405 test-emit-subx-stmt-function-call:
22406     # Call a function on a variable on the stack.
22407     #   f foo
22408     # =>
22409     #   (f *(ebp-8))
22410     # (Changing the function name supports overloading in general, but here it
22411     # just serves to help disambiguate things.)
22412     #
22413     # There's a variable on the var stack as follows:
22414     #   name: 'foo'
22415     #   type: int
22416     #   stack-offset: -8
22417     #
22418     # There's nothing in primitives.
22419     #
22420     # We don't perform any checking here on the type of 'f'.
22421     #
22422     # . prologue
22423     55/push-ebp
22424     89/<- %ebp 4/r32/esp
22425     # setup
22426     (clear-stream _test-output-stream)
22427     (clear-stream $_test-output-buffered-file->buffer)
22428 $test-emit-subx-function-call:initialize-type:
22429     # var type/ecx: (payload type-tree) = int
22430     68/push 0/imm32/right:null
22431     68/push 0/imm32/right:null
22432     68/push 0/imm32/left:unused
22433     68/push 1/imm32/value:int
22434     68/push 1/imm32/is-atom?:true
22435     68/push 0x11/imm32/alloc-id:fake:payload
22436     89/<- %ecx 4/r32/esp
22437 $test-emit-subx-function-call:initialize-var:
22438     # var var-foo/ecx: (payload var) = var(type)
22439     68/push 0/imm32/no-register
22440     68/push 0/imm32/no-register
22441     68/push -8/imm32/stack-offset
22442     68/push 1/imm32/block-depth
22443     51/push-ecx/type
22444     68/push 0x11/imm32/alloc-id:fake
22445     68/push 0/imm32/name
22446     68/push 0/imm32/name
22447     68/push 0x11/imm32/alloc-id:fake:payload
22448     89/<- %ecx 4/r32/esp
22449 $test-emit-subx-function-call:initialize-var-name:
22450     # var-foo->name = "foo"
22451     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22452     (copy-array Heap "foo" %eax)
22453 $test-emit-subx-function-call:initialize-stmt-var:
22454     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
22455     68/push 0/imm32/is-deref:false
22456     68/push 0/imm32/next
22457     68/push 0/imm32/next
22458     51/push-ecx/var-foo
22459     68/push 0x11/imm32/alloc-id:fake
22460     68/push 0x11/imm32/alloc-id:fake:payload
22461     89/<- %ebx 4/r32/esp
22462 $test-emit-subx-function-call:initialize-stmt:
22463     # var stmt/esi: (addr statement)
22464     68/push 0/imm32/no-outputs
22465     68/push 0/imm32/no-outputs
22466     53/push-ebx/inouts
22467     68/push 0x11/imm32/alloc-id:fake
22468     68/push 0/imm32/operation
22469     68/push 0/imm32/operation
22470     68/push 1/imm32/tag
22471     89/<- %esi 4/r32/esp
22472 $test-emit-subx-function-call:initialize-stmt-operation:
22473     # stmt->operation = "f"
22474     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22475     (copy-array Heap "f" %eax)
22476     # convert
22477     c7 0/subop/copy *Curr-block-depth 0/imm32
22478     (emit-subx-stmt _test-output-buffered-file %esi 0 Stderr 0)
22479     (flush _test-output-buffered-file)
22480 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
22486     # check output
22487     (check-next-stream-line-equal _test-output-stream "(f *(ebp+0xfffffff8))" "F - test-emit-subx-stmt-function-call")
22488     # . epilogue
22489     89/<- %esp 5/r32/ebp
22490     5d/pop-to-ebp
22491     c3/return
22492 
22493 test-emit-subx-stmt-function-call-with-literal-arg:
22494     # Call a function on a literal.
22495     #   f 0x34
22496     # =>
22497     #   (f2 0x34)
22498     #
22499     # . prologue
22500     55/push-ebp
22501     89/<- %ebp 4/r32/esp
22502     # setup
22503     (clear-stream _test-output-stream)
22504     (clear-stream $_test-output-buffered-file->buffer)
22505 $test-emit-subx-function-call-with-literal-arg:initialize-type:
22506     # var type/ecx: (payload type-tree) = int
22507     68/push 0/imm32/right:null
22508     68/push 0/imm32/right:null
22509     68/push 0/imm32/left:unused
22510     68/push 0/imm32/value:literal
22511     68/push 1/imm32/is-atom?:true
22512     68/push 0x11/imm32/alloc-id:fake:payload
22513     89/<- %ecx 4/r32/esp
22514 $test-emit-subx-function-call-with-literal-arg:initialize-var:
22515     # var var-foo/ecx: (payload var) = var(lit)
22516     68/push 0/imm32/no-register
22517     68/push 0/imm32/no-register
22518     68/push 0/imm32/no-stack-offset
22519     68/push 1/imm32/block-depth
22520     51/push-ecx/type
22521     68/push 0x11/imm32/alloc-id:fake
22522     68/push 0/imm32/name
22523     68/push 0/imm32/name
22524     68/push 0x11/imm32/alloc-id:fake:payload
22525     89/<- %ecx 4/r32/esp
22526 $test-emit-subx-function-call-with-literal-arg:initialize-var-name:
22527     # var-foo->name = "0x34"
22528     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22529     (copy-array Heap "0x34" %eax)
22530 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-var:
22531     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
22532     68/push 0/imm32/is-deref:false
22533     68/push 0/imm32/next
22534     68/push 0/imm32/next
22535     51/push-ecx/var-foo
22536     68/push 0x11/imm32/alloc-id:fake
22537     68/push 0x11/imm32/alloc-id:fake:payload
22538     89/<- %ebx 4/r32/esp
22539 $test-emit-subx-function-call-with-literal-arg:initialize-stmt:
22540     # var stmt/esi: (addr statement)
22541     68/push 0/imm32/no-outputs
22542     68/push 0/imm32/no-outputs
22543     53/push-ebx/inouts
22544     68/push 0x11/imm32/alloc-id:fake
22545     68/push 0/imm32/operation
22546     68/push 0/imm32/operation
22547     68/push 1/imm32/tag
22548     89/<- %esi 4/r32/esp
22549 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-operation:
22550     # stmt->operation = "f"
22551     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22552     (copy-array Heap "f" %eax)
22553     # convert
22554     c7 0/subop/copy *Curr-block-depth 0/imm32
22555     (emit-subx-stmt _test-output-buffered-file %esi 0 %ebx Stderr 0)
22556     (flush _test-output-buffered-file)
22557 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
22563     # check output
22564     (check-next-stream-line-equal _test-output-stream "(f 0x34)" "F - test-emit-subx-stmt-function-call-with-literal-arg")
22565     # . epilogue
22566     89/<- %esp 5/r32/ebp
22567     5d/pop-to-ebp
22568     c3/return
22569 
22570 emit-indent:  # out: (addr buffered-file), n: int
22571     # . prologue
22572     55/push-ebp
22573     89/<- %ebp 4/r32/esp
22574     # . save registers
22575     50/push-eax
22576     # var i/eax: int = n
22577     8b/-> *(ebp+0xc) 0/r32/eax
22578     {
22579       # if (i <= 0) break
22580       3d/compare-eax-with 0/imm32
22581       7e/jump-if-<= break/disp8
22582       (write-buffered *(ebp+8) "  ")
22583       48/decrement-eax
22584       eb/jump loop/disp8
22585     }
22586 $emit-indent:end:
22587     # . restore registers
22588     58/pop-to-eax
22589     # . epilogue
22590     89/<- %esp 5/r32/ebp
22591     5d/pop-to-ebp
22592     c3/return
22593 
22594 emit-subx-prologue:  # out: (addr buffered-file)
22595     # . prologue
22596     55/push-ebp
22597     89/<- %ebp 4/r32/esp
22598     #
22599     (write-buffered *(ebp+8) "  # . prologue\n")
22600     (write-buffered *(ebp+8) "  55/push-ebp\n")
22601     (write-buffered *(ebp+8) "  89/<- %ebp 4/r32/esp\n")
22602 $emit-subx-prologue:end:
22603     # . epilogue
22604     89/<- %esp 5/r32/ebp
22605     5d/pop-to-ebp
22606     c3/return
22607 
22608 emit-subx-epilogue:  # out: (addr buffered-file)
22609     # . prologue
22610     55/push-ebp
22611     89/<- %ebp 4/r32/esp
22612     #
22613     (write-buffered *(ebp+8) "  # . epilogue\n")
22614     (write-buffered *(ebp+8) "  89/<- %esp 5/r32/ebp\n")
22615     (write-buffered *(ebp+8) "  5d/pop-to-ebp\n")
22616     (write-buffered *(ebp+8) "  c3/return\n")
22617 $emit-subx-epilogue:end:
22618     # . epilogue
22619     89/<- %esp 5/r32/ebp
22620     5d/pop-to-ebp
22621     c3/return