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 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 4320     (check-stream-equal _test-error-stream  ""  "F - test-reg-var-def-with-read-of-same-register: error stream should be empty")
 4321     # check output
 4322     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-reg-var-def-with-read-of-same-register/0")
 4323     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-reg-var-def-with-read-of-same-register/1")
 4324     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-reg-var-def-with-read-of-same-register/2")
 4325     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-reg-var-def-with-read-of-same-register/3")
 4326     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-reg-var-def-with-read-of-same-register/4")
 4327     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-reg-var-def-with-read-of-same-register/5")
 4328     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-reg-var-def-with-read-of-same-register/6")
 4329     (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")
 4330     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-reg-var-def-with-read-of-same-register/8")
 4331     (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")
 4332     (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")
 4333     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-reg-var-def-with-read-of-same-register/13")
 4334     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-reg-var-def-with-read-of-same-register/14")
 4335     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-reg-var-def-with-read-of-same-register/15")
 4336     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-reg-var-def-with-read-of-same-register/16")
 4337     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-reg-var-def-with-read-of-same-register/17")
 4338     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-reg-var-def-with-read-of-same-register/18")
 4339     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-reg-var-def-with-read-of-same-register/19")
 4340     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-reg-var-def-with-read-of-same-register/20")
 4341     # don't restore from ebp
 4342     81 0/subop/add %esp 8/imm32
 4343     # . epilogue
 4344     5d/pop-to-ebp
 4345     c3/return
 4346 
 4347 test-convert-index-into-array:
 4348     # . prologue
 4349     55/push-ebp
 4350     89/<- %ebp 4/r32/esp
 4351     # setup
 4352     (clear-stream _test-input-stream)
 4353     (clear-stream $_test-input-buffered-file->buffer)
 4354     (clear-stream _test-output-stream)
 4355     (clear-stream $_test-output-buffered-file->buffer)
 4356     #
 4357     (write _test-input-stream "fn foo {\n")
 4358     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4359     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4360     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 4361     (write _test-input-stream "}\n")
 4362     # convert
 4363     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4364     (flush _test-output-buffered-file)
 4365 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4371     # check output
 4372     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array/0")
 4373     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array/1")
 4374     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array/2")
 4375     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array/3")
 4376     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array/4")
 4377     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array/5")
 4378     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array/6")
 4379     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array/7")
 4380     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array/8")
 4381     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array/9")
 4382     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx<<0x00000002 + 4) 0x00000000/r32"  "F - test-convert-index-into-array/10")
 4383     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array/11")
 4384     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array/12")
 4385     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array/13")
 4386     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array/14")
 4387     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array/15")
 4388     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array/16")
 4389     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array/17")
 4390     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array/18")
 4391     # . epilogue
 4392     89/<- %esp 5/r32/ebp
 4393     5d/pop-to-ebp
 4394     c3/return
 4395 
 4396 test-convert-index-into-array-of-bytes:
 4397     # . prologue
 4398     55/push-ebp
 4399     89/<- %ebp 4/r32/esp
 4400     # setup
 4401     (clear-stream _test-input-stream)
 4402     (clear-stream $_test-input-buffered-file->buffer)
 4403     (clear-stream _test-output-stream)
 4404     (clear-stream $_test-output-buffered-file->buffer)
 4405     #
 4406     (write _test-input-stream "fn foo {\n")
 4407     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4408     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4409     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, idx\n")
 4410     (write _test-input-stream "}\n")
 4411     # convert
 4412     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4413     (flush _test-output-buffered-file)
 4414 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4420     # check output
 4421     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes/0")
 4422     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes/1")
 4423     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes/2")
 4424     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes/3")
 4425     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes/4")
 4426     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes/5")
 4427     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes/6")
 4428     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-of-bytes/7")
 4429     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes/8")
 4430     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-of-bytes/9")
 4431     (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")
 4432     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes/13")
 4433     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes/14")
 4434     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes/15")
 4435     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes/16")
 4436     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes/17")
 4437     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes/18")
 4438     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes/19")
 4439     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes/20")
 4440     # . epilogue
 4441     89/<- %esp 5/r32/ebp
 4442     5d/pop-to-ebp
 4443     c3/return
 4444 
 4445 test-convert-index-into-array-with-literal:
 4446     # . prologue
 4447     55/push-ebp
 4448     89/<- %ebp 4/r32/esp
 4449     # setup
 4450     (clear-stream _test-input-stream)
 4451     (clear-stream $_test-input-buffered-file->buffer)
 4452     (clear-stream _test-output-stream)
 4453     (clear-stream $_test-output-buffered-file->buffer)
 4454     #
 4455     (write _test-input-stream "fn foo {\n")
 4456     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4457     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
 4458     (write _test-input-stream "}\n")
 4459     # convert
 4460     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4461     (flush _test-output-buffered-file)
 4462 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4468     # check output
 4469     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-with-literal/0")
 4470     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-with-literal/1")
 4471     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-with-literal/2")
 4472     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-with-literal/3")
 4473     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-with-literal/4")
 4474     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-with-literal/5")
 4475     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-with-literal/6")
 4476     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-with-literal/7")
 4477                                                                                  # 2 * 4 bytes/elem + 4 bytes for size = offset 12
 4478     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x0000000c) 0x00000000/r32"  "F - test-convert-index-into-array-with-literal/8")
 4479     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-with-literal/9")
 4480     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-with-literal/10")
 4481     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-with-literal/11")
 4482     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-with-literal/12")
 4483     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-with-literal/13")
 4484     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-with-literal/14")
 4485     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-with-literal/15")
 4486     # . epilogue
 4487     89/<- %esp 5/r32/ebp
 4488     5d/pop-to-ebp
 4489     c3/return
 4490 
 4491 test-convert-index-into-array-of-bytes-with-literal:
 4492     # . prologue
 4493     55/push-ebp
 4494     89/<- %ebp 4/r32/esp
 4495     # setup
 4496     (clear-stream _test-input-stream)
 4497     (clear-stream $_test-input-buffered-file->buffer)
 4498     (clear-stream _test-output-stream)
 4499     (clear-stream $_test-output-buffered-file->buffer)
 4500     #
 4501     (write _test-input-stream "fn foo {\n")
 4502     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4503     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, 2\n")
 4504     (write _test-input-stream "}\n")
 4505     # convert
 4506     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4507     (flush _test-output-buffered-file)
 4508 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4514     # check output
 4515     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-with-literal/0")
 4516     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-with-literal/1")
 4517     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-with-literal/2")
 4518     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-with-literal/3")
 4519     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-with-literal/4")
 4520     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-with-literal/5")
 4521     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-with-literal/6")
 4522     (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")
 4523                                                                                  # 2 * 1 byte/elem + 4 bytes for size = offset 6
 4524     (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")
 4525     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-with-literal/9")
 4526     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-with-literal/10")
 4527     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-with-literal/11")
 4528     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-with-literal/12")
 4529     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-with-literal/13")
 4530     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-with-literal/14")
 4531     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-with-literal/15")
 4532     # . epilogue
 4533     89/<- %esp 5/r32/ebp
 4534     5d/pop-to-ebp
 4535     c3/return
 4536 
 4537 test-convert-index-into-array-on-stack:
 4538     # . prologue
 4539     55/push-ebp
 4540     89/<- %ebp 4/r32/esp
 4541     # setup
 4542     (clear-stream _test-input-stream)
 4543     (clear-stream $_test-input-buffered-file->buffer)
 4544     (clear-stream _test-output-stream)
 4545     (clear-stream $_test-output-buffered-file->buffer)
 4546     #
 4547     (write _test-input-stream "fn foo {\n")
 4548     (write _test-input-stream "  var arr: (array int 3)\n")
 4549     (write _test-input-stream "  var idx/eax: int <- copy 2\n")
 4550     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 4551     (write _test-input-stream "}\n")
 4552     # convert
 4553     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4554     (flush _test-output-buffered-file)
 4555 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4561     # check output
 4562     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack/0")
 4563     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack/1")
 4564     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack/2")
 4565     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack/3")
 4566     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack/4")
 4567     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack/5")
 4568     # var arr
 4569     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack/6")
 4570     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack/7")
 4571     # var idx
 4572     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack/8")
 4573     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 2/imm32"                  "F - test-convert-index-into-array-on-stack/9")
 4574     # var x is at (ebp-0x10) + idx<<2 + 4 = ebp + idx<<2 - 0xc
 4575     (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")
 4576     # reclaim idx
 4577     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack/11")
 4578     # reclaim arr
 4579     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"    "F - test-convert-index-into-array-on-stack/12")
 4580     #
 4581     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack/13")
 4582     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack/14")
 4583     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack/15")
 4584     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack/16")
 4585     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack/17")
 4586     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack/18")
 4587     # . epilogue
 4588     89/<- %esp 5/r32/ebp
 4589     5d/pop-to-ebp
 4590     c3/return
 4591 
 4592 test-convert-index-into-array-on-stack-with-literal:
 4593     # . prologue
 4594     55/push-ebp
 4595     89/<- %ebp 4/r32/esp
 4596     # setup
 4597     (clear-stream _test-input-stream)
 4598     (clear-stream $_test-input-buffered-file->buffer)
 4599     (clear-stream _test-output-stream)
 4600     (clear-stream $_test-output-buffered-file->buffer)
 4601     #
 4602     (write _test-input-stream "fn foo {\n")
 4603     (write _test-input-stream "  var arr: (array int 3)\n")
 4604     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
 4605     (write _test-input-stream "}\n")
 4606     # convert
 4607     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4608     (flush _test-output-buffered-file)
 4609 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4615     # check output
 4616     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack-with-literal/0")
 4617     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack-with-literal/1")
 4618     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack-with-literal/2")
 4619     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack-with-literal/3")
 4620     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack-with-literal/4")
 4621     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack-with-literal/5")
 4622     # var arr
 4623     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack-with-literal/6")
 4624     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack-with-literal/7")
 4625     # var x
 4626     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack-with-literal/8")
 4627     # x is at (ebp-0x10) + 4 + 2*4 = ebp-4
 4628     (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")
 4629     # reclaim x
 4630     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack-with-literal/10")
 4631     # reclaim arr
 4632     (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")
 4633     #
 4634     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack-with-literal/12")
 4635     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack-with-literal/13")
 4636     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack-with-literal/14")
 4637     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack-with-literal/15")
 4638     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack-with-literal/16")
 4639     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack-with-literal/17")
 4640     # . epilogue
 4641     89/<- %esp 5/r32/ebp
 4642     5d/pop-to-ebp
 4643     c3/return
 4644 
 4645 test-convert-index-into-array-of-bytes-on-stack-with-literal:
 4646     # . prologue
 4647     55/push-ebp
 4648     89/<- %ebp 4/r32/esp
 4649     # setup
 4650     (clear-stream _test-input-stream)
 4651     (clear-stream $_test-input-buffered-file->buffer)
 4652     (clear-stream _test-output-stream)
 4653     (clear-stream $_test-output-buffered-file->buffer)
 4654     #
 4655     (write _test-input-stream "fn foo {\n")
 4656     (write _test-input-stream "  var arr: (array byte 3)\n")
 4657     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, 2\n")
 4658     (write _test-input-stream "}\n")
 4659     # convert
 4660     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4661     (flush _test-output-buffered-file)
 4662 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4668     # check output
 4669     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/0")
 4670     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/1")
 4671     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/2")
 4672     (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")
 4673     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/4")
 4674     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/5")
 4675     # var arr
 4676     (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")
 4677     (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")
 4678     # var x
 4679     (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")
 4680     # x is at (ebp-7) + 4 + 2 = ebp-1
 4681     (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")
 4682     # reclaim x
 4683     (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")
 4684     # reclaim arr
 4685     (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")
 4686     #
 4687     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/12")
 4688     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/13")
 4689     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/14")
 4690     (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")
 4691     (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")
 4692     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/17")
 4693     # . epilogue
 4694     89/<- %esp 5/r32/ebp
 4695     5d/pop-to-ebp
 4696     c3/return
 4697 
 4698 test-convert-index-into-array-using-offset:
 4699     # . prologue
 4700     55/push-ebp
 4701     89/<- %ebp 4/r32/esp
 4702     # setup
 4703     (clear-stream _test-input-stream)
 4704     (clear-stream $_test-input-buffered-file->buffer)
 4705     (clear-stream _test-output-stream)
 4706     (clear-stream $_test-output-buffered-file->buffer)
 4707     #
 4708     (write _test-input-stream "fn foo {\n")
 4709     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4710     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4711     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
 4712     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
 4713     (write _test-input-stream "}\n")
 4714     # convert
 4715     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4716     (flush _test-output-buffered-file)
 4717 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4723     # check output
 4724     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset/0")
 4725     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset/1")
 4726     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset/2")
 4727     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset/3")
 4728     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset/4")
 4729     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset/5")
 4730     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset/6")
 4731     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-using-offset/7")
 4732     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset/8")
 4733     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-using-offset/9")
 4734     (check-next-stream-line-equal _test-output-stream "    69/multiply %ecx 0x00000004/imm32 0x00000001/r32"  "F - test-convert-index-into-array-using-offset/10")
 4735     (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")
 4736     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset/12")
 4737     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset/13")
 4738     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset/14")
 4739     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset/15")
 4740     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset/16")
 4741     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset/17")
 4742     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset/18")
 4743     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset/19")
 4744     # . epilogue
 4745     89/<- %esp 5/r32/ebp
 4746     5d/pop-to-ebp
 4747     c3/return
 4748 
 4749 test-convert-index-into-array-of-bytes-using-offset:
 4750     # . prologue
 4751     55/push-ebp
 4752     89/<- %ebp 4/r32/esp
 4753     # setup
 4754     (clear-stream _test-input-stream)
 4755     (clear-stream $_test-input-buffered-file->buffer)
 4756     (clear-stream _test-output-stream)
 4757     (clear-stream $_test-output-buffered-file->buffer)
 4758     #
 4759     (write _test-input-stream "fn foo {\n")
 4760     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4761     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4762     (write _test-input-stream "  var off/ecx: (offset byte) <- compute-offset arr, idx\n")
 4763     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, off\n")
 4764     (write _test-input-stream "}\n")
 4765     # convert
 4766     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4767     (flush _test-output-buffered-file)
 4768 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4774     # check output
 4775     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-using-offset/0")
 4776     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-using-offset/1")
 4777     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-using-offset/2")
 4778     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-using-offset/3")
 4779     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-using-offset/4")
 4780     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-using-offset/5")
 4781     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-using-offset/6")
 4782     (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")
 4783     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes-using-offset/8")
 4784     (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")
 4785     (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")
 4786     (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")
 4787     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes-using-offset/12")
 4788     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-using-offset/13")
 4789     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-using-offset/14")
 4790     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-using-offset/15")
 4791     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-using-offset/16")
 4792     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-using-offset/17")
 4793     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-using-offset/18")
 4794     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-using-offset/19")
 4795     # . epilogue
 4796     89/<- %esp 5/r32/ebp
 4797     5d/pop-to-ebp
 4798     c3/return
 4799 
 4800 test-convert-index-into-array-using-offset-on-stack:
 4801     # . prologue
 4802     55/push-ebp
 4803     89/<- %ebp 4/r32/esp
 4804     # setup
 4805     (clear-stream _test-input-stream)
 4806     (clear-stream $_test-input-buffered-file->buffer)
 4807     (clear-stream _test-output-stream)
 4808     (clear-stream $_test-output-buffered-file->buffer)
 4809     #
 4810     (write _test-input-stream "fn foo {\n")
 4811     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4812     (write _test-input-stream "  var idx: int\n")
 4813     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
 4814     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
 4815     (write _test-input-stream "}\n")
 4816     # convert
 4817     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4818     (flush _test-output-buffered-file)
 4819 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4825     # check output
 4826     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset-on-stack/0")
 4827     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset-on-stack/1")
 4828     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset-on-stack/2")
 4829     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset-on-stack/3")
 4830     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset-on-stack/4")
 4831     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset-on-stack/5")
 4832     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset-on-stack/6")
 4833     (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")
 4834     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"                         "F - test-convert-index-into-array-using-offset-on-stack/8")
 4835     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset-on-stack/9")
 4836     (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")
 4837     (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")
 4838     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset-on-stack/12")
 4839     (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")
 4840     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset-on-stack/14")
 4841     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset-on-stack/15")
 4842     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset-on-stack/16")
 4843     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset-on-stack/17")
 4844     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset-on-stack/18")
 4845     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset-on-stack/19")
 4846     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset-on-stack/20")
 4847     # . epilogue
 4848     89/<- %esp 5/r32/ebp
 4849     5d/pop-to-ebp
 4850     c3/return
 4851 
 4852 test-convert-index-into-array-of-bytes-using-offset-on-stack:
 4853     # . prologue
 4854     55/push-ebp
 4855     89/<- %ebp 4/r32/esp
 4856     # setup
 4857     (clear-stream _test-input-stream)
 4858     (clear-stream $_test-input-buffered-file->buffer)
 4859     (clear-stream _test-output-stream)
 4860     (clear-stream $_test-output-buffered-file->buffer)
 4861     #
 4862     (write _test-input-stream "fn foo {\n")
 4863     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4864     (write _test-input-stream "  var idx: int\n")
 4865     (write _test-input-stream "  var off/ecx: (offset byte) <- compute-offset arr, idx\n")
 4866     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, off\n")
 4867     (write _test-input-stream "}\n")
 4868     # convert
 4869     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4870     (flush _test-output-buffered-file)
 4871 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4877     # check output
 4878     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/0")
 4879     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/1")
 4880     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/2")
 4881     (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")
 4882     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/4")
 4883     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/5")
 4884     (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")
 4885     (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")
 4886     (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")
 4887     (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")
 4888     (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")
 4889     (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")
 4890     (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")
 4891     (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")
 4892     (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")
 4893     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/15")
 4894     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/16")
 4895     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/17")
 4896     (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")
 4897     (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")
 4898     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/20")
 4899     # . epilogue
 4900     89/<- %esp 5/r32/ebp
 4901     5d/pop-to-ebp
 4902     c3/return
 4903 
 4904 test-convert-function-and-type-definition:
 4905     # . prologue
 4906     55/push-ebp
 4907     89/<- %ebp 4/r32/esp
 4908     # setup
 4909     (clear-stream _test-input-stream)
 4910     (clear-stream $_test-input-buffered-file->buffer)
 4911     (clear-stream _test-output-stream)
 4912     (clear-stream $_test-output-buffered-file->buffer)
 4913     #
 4914     (write _test-input-stream "fn foo a: (addr t) {\n")
 4915     (write _test-input-stream "  var _a/eax: (addr t) <- copy a\n")
 4916     (write _test-input-stream "  var b/ecx: (addr int) <- get _a, x\n")
 4917     (write _test-input-stream "  var c/ecx: (addr int) <- get _a, y\n")
 4918     (write _test-input-stream "}\n")
 4919     (write _test-input-stream "type t {\n")
 4920     (write _test-input-stream "  x: int\n")
 4921     (write _test-input-stream "  y: int\n")
 4922     (write _test-input-stream "}\n")
 4923     # convert
 4924     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4925     (flush _test-output-buffered-file)
 4926 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4932     # check output
 4933     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-and-type-definition/0")
 4934     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-and-type-definition/1")
 4935     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-and-type-definition/2")
 4936     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-and-type-definition/3")
 4937     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-and-type-definition/4")
 4938     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-and-type-definition/5")
 4939     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-function-and-type-definition/6")
 4940     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-and-type-definition/7")
 4941     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-and-type-definition/8")
 4942     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000000) 0x00000001/r32"  "F - test-convert-function-and-type-definition/9")
 4943     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000004) 0x00000001/r32"  "F - test-convert-function-and-type-definition/11")
 4944     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-and-type-definition/13")
 4945     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-convert-function-and-type-definition/14")
 4946     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-and-type-definition/15")
 4947     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-and-type-definition/16")
 4948     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-and-type-definition/17")
 4949     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-and-type-definition/18")
 4950     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-and-type-definition/19")
 4951     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-and-type-definition/20")
 4952     # . epilogue
 4953     89/<- %esp 5/r32/ebp
 4954     5d/pop-to-ebp
 4955     c3/return
 4956 
 4957 test-type-definition-with-array:
 4958     # . prologue
 4959     55/push-ebp
 4960     89/<- %ebp 4/r32/esp
 4961     # setup
 4962     (clear-stream _test-input-stream)
 4963     (clear-stream $_test-input-buffered-file->buffer)
 4964     (clear-stream _test-output-stream)
 4965     (clear-stream $_test-output-buffered-file->buffer)
 4966     (clear-stream _test-error-stream)
 4967     (clear-stream $_test-error-buffered-file->buffer)
 4968     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 4969     68/push 0/imm32
 4970     68/push 0/imm32
 4971     89/<- %edx 4/r32/esp
 4972     (tailor-exit-descriptor %edx 0x10)
 4973     #
 4974     (write _test-input-stream "type t {\n")
 4975     (write _test-input-stream "  a: (array int 3)\n")
 4976     (write _test-input-stream "}\n")
 4977     # convert
 4978     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 4979     # registers except esp clobbered at this point
 4980     # restore ed
 4981     89/<- %edx 4/r32/esp
 4982     (flush _test-output-buffered-file)
 4983     (flush _test-error-buffered-file)
 4984 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 4990     # check output
 4991     (check-stream-equal _test-output-stream  ""  "F - test-type-definition-with-array: output should be empty")
 4992     (check-next-stream-line-equal _test-error-stream  "type t: 'array' elements not allowed for now"  "F - test-type-definition-with-array: error message")
 4993     # check that stop(1) was called
 4994     (check-ints-equal *(edx+4) 2 "F - test-type-definition-with-array: exit status")
 4995     # don't restore from ebp
 4996     81 0/subop/add %esp 8/imm32
 4997     # . epilogue
 4998     5d/pop-to-ebp
 4999     c3/return
 5000 
 5001 test-type-definition-with-addr:
 5002     # . prologue
 5003     55/push-ebp
 5004     89/<- %ebp 4/r32/esp
 5005     # setup
 5006     (clear-stream _test-input-stream)
 5007     (clear-stream $_test-input-buffered-file->buffer)
 5008     (clear-stream _test-output-stream)
 5009     (clear-stream $_test-output-buffered-file->buffer)
 5010     (clear-stream _test-error-stream)
 5011     (clear-stream $_test-error-buffered-file->buffer)
 5012     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5013     68/push 0/imm32
 5014     68/push 0/imm32
 5015     89/<- %edx 4/r32/esp
 5016     (tailor-exit-descriptor %edx 0x10)
 5017     #
 5018     (write _test-input-stream "type t {\n")
 5019     (write _test-input-stream "  a: (addr int)\n")
 5020     (write _test-input-stream "}\n")
 5021     # convert
 5022     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5023     # registers except esp clobbered at this point
 5024     # restore ed
 5025     89/<- %edx 4/r32/esp
 5026     (flush _test-output-buffered-file)
 5027     (flush _test-error-buffered-file)
 5028 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5034     # check output
 5035     (check-stream-equal _test-output-stream  ""  "F - test-type-definition-with-addr: output should be empty")
 5036     (check-next-stream-line-equal _test-error-stream  "type t: 'addr' elements not allowed"  "F - test-type-definition-with-addr: error message")
 5037     # check that stop(1) was called
 5038     (check-ints-equal *(edx+4) 2 "F - test-type-definition-with-addr: exit status")
 5039     # don't restore from ebp
 5040     81 0/subop/add %esp 8/imm32
 5041     # . epilogue
 5042     5d/pop-to-ebp
 5043     c3/return
 5044 
 5045 test-convert-function-with-local-var-with-user-defined-type:
 5046     # . prologue
 5047     55/push-ebp
 5048     89/<- %ebp 4/r32/esp
 5049     # setup
 5050     (clear-stream _test-input-stream)
 5051     (clear-stream $_test-input-buffered-file->buffer)
 5052     (clear-stream _test-output-stream)
 5053     (clear-stream $_test-output-buffered-file->buffer)
 5054     #
 5055     (write _test-input-stream "fn foo {\n")
 5056     (write _test-input-stream "  var a: t\n")
 5057     (write _test-input-stream "}\n")
 5058     (write _test-input-stream "type t {\n")
 5059     (write _test-input-stream "  x: int\n")
 5060     (write _test-input-stream "  y: int\n")
 5061     (write _test-input-stream "}\n")
 5062     # convert
 5063     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5064     (flush _test-output-buffered-file)
 5065 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5071     # check output
 5072     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-user-defined-type/0")
 5073     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-user-defined-type/1")
 5074     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-user-defined-type/2")
 5075     (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")
 5076     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-user-defined-type/4")
 5077     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-user-defined-type/5")
 5078     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/6")
 5079     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/7")
 5080     (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")
 5081     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-user-defined-type/9")
 5082     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-user-defined-type/10")
 5083     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-user-defined-type/11")
 5084     (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")
 5085     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-with-user-defined-type/13")
 5086     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-user-defined-type/14")
 5087     # . epilogue
 5088     89/<- %esp 5/r32/ebp
 5089     5d/pop-to-ebp
 5090     c3/return
 5091 
 5092 test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type:
 5093     # . prologue
 5094     55/push-ebp
 5095     89/<- %ebp 4/r32/esp
 5096     # setup
 5097     (clear-stream _test-input-stream)
 5098     (clear-stream $_test-input-buffered-file->buffer)
 5099     (clear-stream _test-output-stream)
 5100     (clear-stream $_test-output-buffered-file->buffer)
 5101     #
 5102     (write _test-input-stream "fn foo {\n")
 5103     (write _test-input-stream "  var a: t\n")
 5104     (write _test-input-stream "}\n")
 5105     (write _test-input-stream "type t {\n")
 5106     (write _test-input-stream "  x: s\n")
 5107     (write _test-input-stream "}\n")
 5108     (write _test-input-stream "type s {\n")
 5109     (write _test-input-stream "  z: int\n")
 5110     (write _test-input-stream "}\n")
 5111     # convert
 5112     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5113     (flush _test-output-buffered-file)
 5114 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5120     # check output
 5121     (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")
 5122     (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")
 5123     (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")
 5124     (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")
 5125     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/4")
 5126     (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")
 5127     (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")
 5128     (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")
 5129     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/9")
 5130     (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")
 5131     (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")
 5132     (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")
 5133     (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")
 5134     (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")
 5135     # . epilogue
 5136     89/<- %esp 5/r32/ebp
 5137     5d/pop-to-ebp
 5138     c3/return
 5139 
 5140 test-convert-function-call-with-arg-of-user-defined-type:
 5141     # . prologue
 5142     55/push-ebp
 5143     89/<- %ebp 4/r32/esp
 5144     # setup
 5145     (clear-stream _test-input-stream)
 5146     (clear-stream $_test-input-buffered-file->buffer)
 5147     (clear-stream _test-output-stream)
 5148     (clear-stream $_test-output-buffered-file->buffer)
 5149     #
 5150     (write _test-input-stream "fn f {\n")
 5151     (write _test-input-stream "  var a: t\n")
 5152     (write _test-input-stream "  foo a\n")
 5153     (write _test-input-stream "}\n")
 5154     (write _test-input-stream "fn foo x: t {\n")
 5155     (write _test-input-stream "}\n")
 5156     (write _test-input-stream "type t {\n")
 5157     (write _test-input-stream "  x: int\n")
 5158     (write _test-input-stream "  y: int\n")
 5159     (write _test-input-stream "}\n")
 5160     # convert
 5161     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5162     (flush _test-output-buffered-file)
 5163 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5169     # check output
 5170     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
 5171     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
 5172     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
 5173     (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")
 5174     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
 5175     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
 5176     # var a: t
 5177     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/6")
 5178     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/7")
 5179     # foo a
 5180     (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")
 5181     #
 5182     (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")
 5183     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
 5184     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
 5185     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
 5186     (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")
 5187     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
 5188     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
 5189     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
 5190     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
 5191     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
 5192     (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")
 5193     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
 5194     (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")
 5195     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
 5196     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
 5197     # . epilogue
 5198     89/<- %esp 5/r32/ebp
 5199     5d/pop-to-ebp
 5200     c3/return
 5201 
 5202 test-convert-function-call-with-arg-of-user-defined-type-register-indirect:
 5203     # . prologue
 5204     55/push-ebp
 5205     89/<- %ebp 4/r32/esp
 5206     # setup
 5207     (clear-stream _test-input-stream)
 5208     (clear-stream $_test-input-buffered-file->buffer)
 5209     (clear-stream _test-output-stream)
 5210     (clear-stream $_test-output-buffered-file->buffer)
 5211     #
 5212     (write _test-input-stream "fn f {\n")
 5213     (write _test-input-stream "  var a/eax: (addr t) <- copy 0\n")
 5214     (write _test-input-stream "  foo *a\n")
 5215     (write _test-input-stream "}\n")
 5216     (write _test-input-stream "fn foo x: t {\n")
 5217     (write _test-input-stream "}\n")
 5218     (write _test-input-stream "type t {\n")
 5219     (write _test-input-stream "  x: int\n")
 5220     (write _test-input-stream "  y: int\n")
 5221     (write _test-input-stream "}\n")
 5222     # convert
 5223     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5224     (flush _test-output-buffered-file)
 5225 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5231     # check output
 5232     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
 5233     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
 5234     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
 5235     (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")
 5236     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
 5237     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
 5238     # var a
 5239     (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")
 5240     (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")
 5241     # foo a
 5242     (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")
 5243     #
 5244     (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")
 5245     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
 5246     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
 5247     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
 5248     (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")
 5249     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
 5250     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
 5251     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
 5252     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
 5253     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
 5254     (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")
 5255     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
 5256     (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")
 5257     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
 5258     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
 5259     # . epilogue
 5260     89/<- %esp 5/r32/ebp
 5261     5d/pop-to-ebp
 5262     c3/return
 5263 
 5264 # we don't have special support for call-by-reference; just explicitly create
 5265 # a new variable with the address of the arg
 5266 test-convert-function-call-with-arg-of-user-defined-type-by-reference:
 5267     # . prologue
 5268     55/push-ebp
 5269     89/<- %ebp 4/r32/esp
 5270     # setup
 5271     (clear-stream _test-input-stream)
 5272     (clear-stream $_test-input-buffered-file->buffer)
 5273     (clear-stream _test-output-stream)
 5274     (clear-stream $_test-output-buffered-file->buffer)
 5275     #
 5276     (write _test-input-stream "fn f {\n")
 5277     (write _test-input-stream "  var a: t\n")
 5278     (write _test-input-stream "  var b/eax: (addr t) <- address a\n")
 5279     (write _test-input-stream "  foo b\n")
 5280     (write _test-input-stream "}\n")
 5281     (write _test-input-stream "fn foo x: (addr t) {\n")
 5282     (write _test-input-stream "  var x/ecx: (addr int) <- copy x\n")
 5283     (write _test-input-stream "  increment *x\n")
 5284     (write _test-input-stream "}\n")
 5285     (write _test-input-stream "type t {\n")
 5286     (write _test-input-stream "  x: int\n")
 5287     (write _test-input-stream "  y: int\n")
 5288     (write _test-input-stream "}\n")
 5289     # convert
 5290     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5291     (flush _test-output-buffered-file)
 5292 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5298     # check output
 5299     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/0")
 5300     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/1")
 5301     (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")
 5302     (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")
 5303     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/4")
 5304     (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")
 5305     # var a: t
 5306     (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")
 5307     (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")
 5308     # var b/eax: (addr t)
 5309     (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")
 5310     (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")
 5311     # foo a
 5312     (check-next-stream-line-equal _test-output-stream "    (foo %eax)"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/10")
 5313     #
 5314     (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")
 5315     (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")
 5316     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/13")
 5317     (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")
 5318     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/15")
 5319     (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")
 5320     (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")
 5321     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/18")
 5322     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/19")
 5323     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/20")
 5324     (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")
 5325     (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")
 5326     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/23")
 5327     (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")
 5328     (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")
 5329     (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")
 5330     (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")
 5331     (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")
 5332     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/29")
 5333     (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")
 5334     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/31")
 5335     (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")
 5336     (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")
 5337     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/34")
 5338     # . epilogue
 5339     89/<- %esp 5/r32/ebp
 5340     5d/pop-to-ebp
 5341     c3/return
 5342 
 5343 test-convert-get-on-local-variable:
 5344     # . prologue
 5345     55/push-ebp
 5346     89/<- %ebp 4/r32/esp
 5347     # setup
 5348     (clear-stream _test-input-stream)
 5349     (clear-stream $_test-input-buffered-file->buffer)
 5350     (clear-stream _test-output-stream)
 5351     (clear-stream $_test-output-buffered-file->buffer)
 5352     #
 5353     (write _test-input-stream "fn foo {\n")
 5354     (write _test-input-stream "  var a: t\n")
 5355     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5356     (write _test-input-stream "}\n")
 5357     (write _test-input-stream "type t {\n")
 5358     (write _test-input-stream "  x: int\n")
 5359     (write _test-input-stream "  y: int\n")
 5360     (write _test-input-stream "}\n")
 5361     # convert
 5362     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5363     (flush _test-output-buffered-file)
 5364 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5370     # check output
 5371     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-local-variable/0")
 5372     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-local-variable/1")
 5373     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-local-variable/2")
 5374     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-local-variable/3")
 5375     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-local-variable/4")
 5376     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-local-variable/5")
 5377     # var a
 5378     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/6")
 5379     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/7")
 5380     # var c
 5381     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-local-variable/8")
 5382     # get
 5383     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000001/r32"  "F - test-convert-get-on-local-variable/9")
 5384     # reclaim c
 5385     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-local-variable/10")
 5386     # reclaim a
 5387     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000008/imm32"  "F - test-convert-get-on-local-variable/11")
 5388     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-local-variable/12")
 5389     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-local-variable/13")
 5390     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-local-variable/14")
 5391     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-local-variable/15")
 5392     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-local-variable/16")
 5393     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-local-variable/17")
 5394     # . epilogue
 5395     89/<- %esp 5/r32/ebp
 5396     5d/pop-to-ebp
 5397     c3/return
 5398 
 5399 test-convert-get-on-function-argument:
 5400     # . prologue
 5401     55/push-ebp
 5402     89/<- %ebp 4/r32/esp
 5403     # setup
 5404     (clear-stream _test-input-stream)
 5405     (clear-stream $_test-input-buffered-file->buffer)
 5406     (clear-stream _test-output-stream)
 5407     (clear-stream $_test-output-buffered-file->buffer)
 5408     #
 5409     (write _test-input-stream "fn foo a: t {\n")
 5410     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5411     (write _test-input-stream "}\n")
 5412     (write _test-input-stream "type t {\n")
 5413     (write _test-input-stream "  x: int\n")
 5414     (write _test-input-stream "  y: int\n")
 5415     (write _test-input-stream "}\n")
 5416     # convert
 5417     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5418     (flush _test-output-buffered-file)
 5419 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5425     # check output
 5426     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument/0")
 5427     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument/1")
 5428     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument/2")
 5429     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument/3")
 5430     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument/4")
 5431     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument/5")
 5432     # var c
 5433     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument/6")
 5434     # get
 5435     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0x0000000c) 0x00000001/r32"  "F - test-convert-get-on-function-argument/7")
 5436     # reclaim c
 5437     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument/8")
 5438     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument/9")
 5439     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument/10")
 5440     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument/11")
 5441     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument/12")
 5442     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument/13")
 5443     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument/14")
 5444     # . epilogue
 5445     89/<- %esp 5/r32/ebp
 5446     5d/pop-to-ebp
 5447     c3/return
 5448 
 5449 test-convert-get-on-function-argument-with-known-type:
 5450     # . prologue
 5451     55/push-ebp
 5452     89/<- %ebp 4/r32/esp
 5453     # setup
 5454     (clear-stream _test-input-stream)
 5455     (clear-stream $_test-input-buffered-file->buffer)
 5456     (clear-stream _test-output-stream)
 5457     (clear-stream $_test-output-buffered-file->buffer)
 5458     #
 5459     (write _test-input-stream "type t {\n")
 5460     (write _test-input-stream "  x: int\n")
 5461     (write _test-input-stream "  y: int\n")
 5462     (write _test-input-stream "}\n")
 5463     (write _test-input-stream "fn foo a: t {\n")
 5464     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5465     (write _test-input-stream "}\n")
 5466     # convert
 5467     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5468     (flush _test-output-buffered-file)
 5469 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5475     # check output
 5476     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument-with-known-type/0")
 5477     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument-with-known-type/1")
 5478     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument-with-known-type/2")
 5479     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument-with-known-type/3")
 5480     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument-with-known-type/4")
 5481     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument-with-known-type/5")
 5482     # var c
 5483     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument-with-known-type/6")
 5484     # get
 5485     (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")
 5486     # reclaim c
 5487     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument-with-known-type/8")
 5488     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument-with-known-type/9")
 5489     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument-with-known-type/10")
 5490     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument-with-known-type/11")
 5491     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument-with-known-type/12")
 5492     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument-with-known-type/13")
 5493     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument-with-known-type/14")
 5494     # . epilogue
 5495     89/<- %esp 5/r32/ebp
 5496     5d/pop-to-ebp
 5497     c3/return
 5498 
 5499 test-add-with-too-many-inouts:
 5500     # . prologue
 5501     55/push-ebp
 5502     89/<- %ebp 4/r32/esp
 5503     # setup
 5504     (clear-stream _test-input-stream)
 5505     (clear-stream $_test-input-buffered-file->buffer)
 5506     (clear-stream _test-output-stream)
 5507     (clear-stream $_test-output-buffered-file->buffer)
 5508     (clear-stream _test-error-stream)
 5509     (clear-stream $_test-error-buffered-file->buffer)
 5510     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5511     68/push 0/imm32
 5512     68/push 0/imm32
 5513     89/<- %edx 4/r32/esp
 5514     (tailor-exit-descriptor %edx 0x10)
 5515     #
 5516     (write _test-input-stream "fn foo {\n")
 5517     (write _test-input-stream "  var a: int\n")
 5518     (write _test-input-stream "  var b/ecx: int <- add a, 0\n")
 5519     (write _test-input-stream "}\n")
 5520     # convert
 5521     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5522     # registers except esp clobbered at this point
 5523     # restore ed
 5524     89/<- %edx 4/r32/esp
 5525     (flush _test-output-buffered-file)
 5526     (flush _test-error-buffered-file)
 5527 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5533     # check output
 5534     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-inouts: output should be empty")
 5535     (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")
 5536     # check that stop(1) was called
 5537     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-inouts: exit status")
 5538     # don't restore from ebp
 5539     81 0/subop/add %esp 8/imm32
 5540     # . epilogue
 5541     5d/pop-to-ebp
 5542     c3/return
 5543 
 5544 test-add-with-too-many-inouts-2:
 5545     # . prologue
 5546     55/push-ebp
 5547     89/<- %ebp 4/r32/esp
 5548     # setup
 5549     (clear-stream _test-input-stream)
 5550     (clear-stream $_test-input-buffered-file->buffer)
 5551     (clear-stream _test-output-stream)
 5552     (clear-stream $_test-output-buffered-file->buffer)
 5553     (clear-stream _test-error-stream)
 5554     (clear-stream $_test-error-buffered-file->buffer)
 5555     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5556     68/push 0/imm32
 5557     68/push 0/imm32
 5558     89/<- %edx 4/r32/esp
 5559     (tailor-exit-descriptor %edx 0x10)
 5560     #
 5561     (write _test-input-stream "fn foo {\n")
 5562     (write _test-input-stream "  var a: int\n")
 5563     (write _test-input-stream "  add-to a, 0, 1\n")
 5564     (write _test-input-stream "}\n")
 5565     # convert
 5566     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5567     # registers except esp clobbered at this point
 5568     # restore ed
 5569     89/<- %edx 4/r32/esp
 5570     (flush _test-output-buffered-file)
 5571     (flush _test-error-buffered-file)
 5572 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5578     # check output
 5579     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-inouts-2: output should be empty")
 5580     (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")
 5581     # check that stop(1) was called
 5582     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-inouts-2: exit status")
 5583     # don't restore from ebp
 5584     81 0/subop/add %esp 8/imm32
 5585     # . epilogue
 5586     5d/pop-to-ebp
 5587     c3/return
 5588 
 5589 test-add-with-too-many-outputs:
 5590     # . prologue
 5591     55/push-ebp
 5592     89/<- %ebp 4/r32/esp
 5593     # setup
 5594     (clear-stream _test-input-stream)
 5595     (clear-stream $_test-input-buffered-file->buffer)
 5596     (clear-stream _test-output-stream)
 5597     (clear-stream $_test-output-buffered-file->buffer)
 5598     (clear-stream _test-error-stream)
 5599     (clear-stream $_test-error-buffered-file->buffer)
 5600     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5601     68/push 0/imm32
 5602     68/push 0/imm32
 5603     89/<- %edx 4/r32/esp
 5604     (tailor-exit-descriptor %edx 0x10)
 5605     #
 5606     (write _test-input-stream "fn foo {\n")
 5607     (write _test-input-stream "  var a/eax: int <- copy 0\n")
 5608     (write _test-input-stream "  var b/ebx: int <- copy 0\n")
 5609     (write _test-input-stream "  var c/ecx: int <- copy 0\n")
 5610     (write _test-input-stream "  c, b <- add a\n")
 5611     (write _test-input-stream "}\n")
 5612     # convert
 5613     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5614     # registers except esp clobbered at this point
 5615     # restore ed
 5616     89/<- %edx 4/r32/esp
 5617     (flush _test-output-buffered-file)
 5618     (flush _test-error-buffered-file)
 5619 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5625     # check output
 5626     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-outputs: output should be empty")
 5627     (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")
 5628     # check that stop(1) was called
 5629     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-outputs: exit status")
 5630     # don't restore from ebp
 5631     81 0/subop/add %esp 8/imm32
 5632     # . epilogue
 5633     5d/pop-to-ebp
 5634     c3/return
 5635 
 5636 test-add-with-non-number:
 5637     # . prologue
 5638     55/push-ebp
 5639     89/<- %ebp 4/r32/esp
 5640     # setup
 5641     (clear-stream _test-input-stream)
 5642     (clear-stream $_test-input-buffered-file->buffer)
 5643     (clear-stream _test-output-stream)
 5644     (clear-stream $_test-output-buffered-file->buffer)
 5645     (clear-stream _test-error-stream)
 5646     (clear-stream $_test-error-buffered-file->buffer)
 5647     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5648     68/push 0/imm32
 5649     68/push 0/imm32
 5650     89/<- %edx 4/r32/esp
 5651     (tailor-exit-descriptor %edx 0x10)
 5652     #
 5653     (write _test-input-stream "fn foo {\n")
 5654     (write _test-input-stream "  var a: int\n")
 5655     (write _test-input-stream "  var b/ecx: (addr int) <- add a\n")
 5656     (write _test-input-stream "}\n")
 5657     # convert
 5658     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5659     # registers except esp clobbered at this point
 5660     # restore ed
 5661     89/<- %edx 4/r32/esp
 5662     (flush _test-output-buffered-file)
 5663     (flush _test-error-buffered-file)
 5664 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5670     # check output
 5671     (check-stream-equal _test-output-stream  ""  "F - test-add-with-non-number: output should be empty")
 5672     (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")
 5673     # check that stop(1) was called
 5674     (check-ints-equal *(edx+4) 2 "F - test-add-with-non-number: exit status")
 5675     # don't restore from ebp
 5676     81 0/subop/add %esp 8/imm32
 5677     # . epilogue
 5678     5d/pop-to-ebp
 5679     c3/return
 5680 
 5681 test-add-with-addr-dereferenced:
 5682     # . prologue
 5683     55/push-ebp
 5684     89/<- %ebp 4/r32/esp
 5685     # setup
 5686     (clear-stream _test-input-stream)
 5687     (clear-stream $_test-input-buffered-file->buffer)
 5688     (clear-stream _test-output-stream)
 5689     (clear-stream $_test-output-buffered-file->buffer)
 5690     #
 5691     (write _test-input-stream "fn foo {\n")
 5692     (write _test-input-stream "  var a/eax: (addr int) <- copy 0\n")
 5693     (write _test-input-stream "  add-to *a, 1\n")
 5694     (write _test-input-stream "}\n")
 5695     # convert
 5696     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5697     (flush _test-output-buffered-file)
 5698     # no error
 5699     # . epilogue
 5700     89/<- %esp 5/r32/ebp
 5701     5d/pop-to-ebp
 5702     c3/return
 5703 
 5704 test-get-with-wrong-field:
 5705     # . prologue
 5706     55/push-ebp
 5707     89/<- %ebp 4/r32/esp
 5708     # setup
 5709     (clear-stream _test-input-stream)
 5710     (clear-stream $_test-input-buffered-file->buffer)
 5711     (clear-stream _test-output-stream)
 5712     (clear-stream $_test-output-buffered-file->buffer)
 5713     (clear-stream _test-error-stream)
 5714     (clear-stream $_test-error-buffered-file->buffer)
 5715     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5716     68/push 0/imm32
 5717     68/push 0/imm32
 5718     89/<- %edx 4/r32/esp
 5719     (tailor-exit-descriptor %edx 0x10)
 5720     #
 5721     (write _test-input-stream "fn foo {\n")
 5722     (write _test-input-stream "  var a: t\n")
 5723     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5724     (write _test-input-stream "}\n")
 5725     (write _test-input-stream "type t {\n")
 5726     (write _test-input-stream "  x: int\n")
 5727     (write _test-input-stream "}\n")
 5728     # convert
 5729     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5730     # registers except esp clobbered at this point
 5731     # restore ed
 5732     89/<- %edx 4/r32/esp
 5733     (flush _test-output-buffered-file)
 5734     (flush _test-error-buffered-file)
 5735 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5741     # check output
 5742     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-field: output should be empty")
 5743     (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")
 5744     # check that stop(1) was called
 5745     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-field: exit status")
 5746     # don't restore from ebp
 5747     81 0/subop/add %esp 8/imm32
 5748     # . epilogue
 5749     5d/pop-to-ebp
 5750     c3/return
 5751 
 5752 test-get-with-wrong-base-type:
 5753     # . prologue
 5754     55/push-ebp
 5755     89/<- %ebp 4/r32/esp
 5756     # setup
 5757     (clear-stream _test-input-stream)
 5758     (clear-stream $_test-input-buffered-file->buffer)
 5759     (clear-stream _test-output-stream)
 5760     (clear-stream $_test-output-buffered-file->buffer)
 5761     (clear-stream _test-error-stream)
 5762     (clear-stream $_test-error-buffered-file->buffer)
 5763     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5764     68/push 0/imm32
 5765     68/push 0/imm32
 5766     89/<- %edx 4/r32/esp
 5767     (tailor-exit-descriptor %edx 0x10)
 5768     #
 5769     (write _test-input-stream "fn foo {\n")
 5770     (write _test-input-stream "  var a: int\n")
 5771     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5772     (write _test-input-stream "}\n")
 5773     # convert
 5774     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5775     # registers except esp clobbered at this point
 5776     # restore ed
 5777     89/<- %edx 4/r32/esp
 5778     (flush _test-output-buffered-file)
 5779     (flush _test-error-buffered-file)
 5780 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5786     # check output
 5787     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-base-type: output should be empty")
 5788     (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")
 5789     # check that stop(1) was called
 5790     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-base-type: exit status")
 5791     # don't restore from ebp
 5792     81 0/subop/add %esp 8/imm32
 5793     # . epilogue
 5794     5d/pop-to-ebp
 5795     c3/return
 5796 
 5797 test-get-with-wrong-base-type-2:
 5798     # . prologue
 5799     55/push-ebp
 5800     89/<- %ebp 4/r32/esp
 5801     # setup
 5802     (clear-stream _test-input-stream)
 5803     (clear-stream $_test-input-buffered-file->buffer)
 5804     (clear-stream _test-output-stream)
 5805     (clear-stream $_test-output-buffered-file->buffer)
 5806     (clear-stream _test-error-stream)
 5807     (clear-stream $_test-error-buffered-file->buffer)
 5808     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5809     68/push 0/imm32
 5810     68/push 0/imm32
 5811     89/<- %edx 4/r32/esp
 5812     (tailor-exit-descriptor %edx 0x10)
 5813     #
 5814     (write _test-input-stream "fn foo {\n")
 5815     (write _test-input-stream "  var a: (addr t)\n")
 5816     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5817     (write _test-input-stream "}\n")
 5818     (write _test-input-stream "type t {\n")
 5819     (write _test-input-stream "  x: int\n")
 5820     (write _test-input-stream "}\n")
 5821     # convert
 5822     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5823     # registers except esp clobbered at this point
 5824     # restore ed
 5825     89/<- %edx 4/r32/esp
 5826     (flush _test-output-buffered-file)
 5827     (flush _test-error-buffered-file)
 5828 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5834     # check output
 5835     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-base-type-2: output should be empty")
 5836     (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")
 5837     # check that stop(1) was called
 5838     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-base-type-2: exit status")
 5839     # don't restore from ebp
 5840     81 0/subop/add %esp 8/imm32
 5841     # . epilogue
 5842     5d/pop-to-ebp
 5843     c3/return
 5844 
 5845 test-get-with-wrong-offset-type:
 5846     # . prologue
 5847     55/push-ebp
 5848     89/<- %ebp 4/r32/esp
 5849     # setup
 5850     (clear-stream _test-input-stream)
 5851     (clear-stream $_test-input-buffered-file->buffer)
 5852     (clear-stream _test-output-stream)
 5853     (clear-stream $_test-output-buffered-file->buffer)
 5854     (clear-stream _test-error-stream)
 5855     (clear-stream $_test-error-buffered-file->buffer)
 5856     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5857     68/push 0/imm32
 5858     68/push 0/imm32
 5859     89/<- %edx 4/r32/esp
 5860     (tailor-exit-descriptor %edx 0x10)
 5861     #
 5862     (write _test-input-stream "fn foo {\n")
 5863     (write _test-input-stream "  var a: t\n")
 5864     (write _test-input-stream "  var b: int\n")
 5865     (write _test-input-stream "  var c/ecx: (addr int) <- get a, b\n")
 5866     (write _test-input-stream "}\n")
 5867     (write _test-input-stream "type t {\n")
 5868     (write _test-input-stream "  x: int\n")
 5869     (write _test-input-stream "}\n")
 5870     # convert
 5871     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5872     # registers except esp clobbered at this point
 5873     # restore ed
 5874     89/<- %edx 4/r32/esp
 5875     (flush _test-output-buffered-file)
 5876     (flush _test-error-buffered-file)
 5877 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5883     # check output
 5884     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-offset-type: output should be empty")
 5885     (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")
 5886     # check that stop(1) was called
 5887     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-offset-type: exit status")
 5888     # don't restore from ebp
 5889     81 0/subop/add %esp 8/imm32
 5890     # . epilogue
 5891     5d/pop-to-ebp
 5892     c3/return
 5893 
 5894 test-get-with-wrong-output-type:
 5895     # . prologue
 5896     55/push-ebp
 5897     89/<- %ebp 4/r32/esp
 5898     # setup
 5899     (clear-stream _test-input-stream)
 5900     (clear-stream $_test-input-buffered-file->buffer)
 5901     (clear-stream _test-output-stream)
 5902     (clear-stream $_test-output-buffered-file->buffer)
 5903     (clear-stream _test-error-stream)
 5904     (clear-stream $_test-error-buffered-file->buffer)
 5905     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5906     68/push 0/imm32
 5907     68/push 0/imm32
 5908     89/<- %edx 4/r32/esp
 5909     (tailor-exit-descriptor %edx 0x10)
 5910     #
 5911     (write _test-input-stream "fn foo {\n")
 5912     (write _test-input-stream "  var a: t\n")
 5913     (write _test-input-stream "  var c: (addr int)\n")
 5914     (write _test-input-stream "  c <- get a, x\n")
 5915     (write _test-input-stream "}\n")
 5916     (write _test-input-stream "type t {\n")
 5917     (write _test-input-stream "  x: int\n")
 5918     (write _test-input-stream "}\n")
 5919     # convert
 5920     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5921     # registers except esp clobbered at this point
 5922     # restore ed
 5923     89/<- %edx 4/r32/esp
 5924     (flush _test-output-buffered-file)
 5925     (flush _test-error-buffered-file)
 5926 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5932     # check output
 5933     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type: output should be empty")
 5934     (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")
 5935     # check that stop(1) was called
 5936     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type: exit status")
 5937     # don't restore from ebp
 5938     81 0/subop/add %esp 8/imm32
 5939     # . epilogue
 5940     5d/pop-to-ebp
 5941     c3/return
 5942 
 5943 test-get-with-wrong-output-type-2:
 5944     # . prologue
 5945     55/push-ebp
 5946     89/<- %ebp 4/r32/esp
 5947     # setup
 5948     (clear-stream _test-input-stream)
 5949     (clear-stream $_test-input-buffered-file->buffer)
 5950     (clear-stream _test-output-stream)
 5951     (clear-stream $_test-output-buffered-file->buffer)
 5952     (clear-stream _test-error-stream)
 5953     (clear-stream $_test-error-buffered-file->buffer)
 5954     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5955     68/push 0/imm32
 5956     68/push 0/imm32
 5957     89/<- %edx 4/r32/esp
 5958     (tailor-exit-descriptor %edx 0x10)
 5959     #
 5960     (write _test-input-stream "fn foo {\n")
 5961     (write _test-input-stream "  var a: t\n")
 5962     (write _test-input-stream "  var c/ecx: int <- get a, x\n")
 5963     (write _test-input-stream "}\n")
 5964     (write _test-input-stream "type t {\n")
 5965     (write _test-input-stream "  x: int\n")
 5966     (write _test-input-stream "}\n")
 5967     # convert
 5968     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5969     # registers except esp clobbered at this point
 5970     # restore ed
 5971     89/<- %edx 4/r32/esp
 5972     (flush _test-output-buffered-file)
 5973     (flush _test-error-buffered-file)
 5974 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5980     # check output
 5981     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-2: output should be empty")
 5982     (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")
 5983     # check that stop(1) was called
 5984     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-2: exit status")
 5985     # don't restore from ebp
 5986     81 0/subop/add %esp 8/imm32
 5987     # . epilogue
 5988     5d/pop-to-ebp
 5989     c3/return
 5990 
 5991 test-get-with-wrong-output-type-3:
 5992     # . prologue
 5993     55/push-ebp
 5994     89/<- %ebp 4/r32/esp
 5995     # setup
 5996     (clear-stream _test-input-stream)
 5997     (clear-stream $_test-input-buffered-file->buffer)
 5998     (clear-stream _test-output-stream)
 5999     (clear-stream $_test-output-buffered-file->buffer)
 6000     (clear-stream _test-error-stream)
 6001     (clear-stream $_test-error-buffered-file->buffer)
 6002     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6003     68/push 0/imm32
 6004     68/push 0/imm32
 6005     89/<- %edx 4/r32/esp
 6006     (tailor-exit-descriptor %edx 0x10)
 6007     #
 6008     (write _test-input-stream "fn foo {\n")
 6009     (write _test-input-stream "  var a: t\n")
 6010     (write _test-input-stream "  var c/ecx: (array int) <- get a, x\n")
 6011     (write _test-input-stream "}\n")
 6012     (write _test-input-stream "type t {\n")
 6013     (write _test-input-stream "  x: int\n")
 6014     (write _test-input-stream "}\n")
 6015     # convert
 6016     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6017     # registers except esp clobbered at this point
 6018     # restore ed
 6019     89/<- %edx 4/r32/esp
 6020     (flush _test-output-buffered-file)
 6021     (flush _test-error-buffered-file)
 6022 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6028     # check output
 6029     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-3: output should be empty")
 6030     (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")
 6031     # check that stop(1) was called
 6032     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-3: exit status")
 6033     # don't restore from ebp
 6034     81 0/subop/add %esp 8/imm32
 6035     # . epilogue
 6036     5d/pop-to-ebp
 6037     c3/return
 6038 
 6039 test-get-with-wrong-output-type-4:
 6040     # . prologue
 6041     55/push-ebp
 6042     89/<- %ebp 4/r32/esp
 6043     # setup
 6044     (clear-stream _test-input-stream)
 6045     (clear-stream $_test-input-buffered-file->buffer)
 6046     (clear-stream _test-output-stream)
 6047     (clear-stream $_test-output-buffered-file->buffer)
 6048     (clear-stream _test-error-stream)
 6049     (clear-stream $_test-error-buffered-file->buffer)
 6050     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6051     68/push 0/imm32
 6052     68/push 0/imm32
 6053     89/<- %edx 4/r32/esp
 6054     (tailor-exit-descriptor %edx 0x10)
 6055     #
 6056     (write _test-input-stream "fn foo {\n")
 6057     (write _test-input-stream "  var a: t\n")
 6058     (write _test-input-stream "  var c/ecx: (addr boolean) <- get a, x\n")
 6059     (write _test-input-stream "}\n")
 6060     (write _test-input-stream "type t {\n")
 6061     (write _test-input-stream "  x: int\n")
 6062     (write _test-input-stream "}\n")
 6063     # convert
 6064     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6065     # registers except esp clobbered at this point
 6066     # restore ed
 6067     89/<- %edx 4/r32/esp
 6068     (flush _test-output-buffered-file)
 6069     (flush _test-error-buffered-file)
 6070 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6076     # check output
 6077     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-4: output should be empty")
 6078     (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")
 6079     # check that stop(1) was called
 6080     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-4: exit status")
 6081     # don't restore from ebp
 6082     81 0/subop/add %esp 8/imm32
 6083     # . epilogue
 6084     5d/pop-to-ebp
 6085     c3/return
 6086 
 6087 test-get-with-wrong-output-type-5:
 6088     # . prologue
 6089     55/push-ebp
 6090     89/<- %ebp 4/r32/esp
 6091     # setup
 6092     (clear-stream _test-input-stream)
 6093     (clear-stream $_test-input-buffered-file->buffer)
 6094     (clear-stream _test-output-stream)
 6095     (clear-stream $_test-output-buffered-file->buffer)
 6096     #
 6097     (write _test-input-stream "fn foo {\n")
 6098     (write _test-input-stream "  var a: t\n")
 6099     (write _test-input-stream "  var c/ecx: (addr handle int) <- get a, x\n")
 6100     (write _test-input-stream "}\n")
 6101     (write _test-input-stream "type t {\n")
 6102     (write _test-input-stream "  x: (handle int)\n")
 6103     (write _test-input-stream "}\n")
 6104     # convert
 6105     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6106     (flush _test-output-buffered-file)
 6107     # no errors
 6108     # . epilogue
 6109     89/<- %esp 5/r32/ebp
 6110     5d/pop-to-ebp
 6111     c3/return
 6112 
 6113 test-get-with-too-few-inouts:
 6114     # . prologue
 6115     55/push-ebp
 6116     89/<- %ebp 4/r32/esp
 6117     # setup
 6118     (clear-stream _test-input-stream)
 6119     (clear-stream $_test-input-buffered-file->buffer)
 6120     (clear-stream _test-output-stream)
 6121     (clear-stream $_test-output-buffered-file->buffer)
 6122     (clear-stream _test-error-stream)
 6123     (clear-stream $_test-error-buffered-file->buffer)
 6124     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6125     68/push 0/imm32
 6126     68/push 0/imm32
 6127     89/<- %edx 4/r32/esp
 6128     (tailor-exit-descriptor %edx 0x10)
 6129     #
 6130     (write _test-input-stream "fn foo {\n")
 6131     (write _test-input-stream "  var a: t\n")
 6132     (write _test-input-stream "  var c/ecx: (addr int) <- get a\n")
 6133     (write _test-input-stream "}\n")
 6134     (write _test-input-stream "type t {\n")
 6135     (write _test-input-stream "  x: int\n")
 6136     (write _test-input-stream "}\n")
 6137     # convert
 6138     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6139     # registers except esp clobbered at this point
 6140     # restore ed
 6141     89/<- %edx 4/r32/esp
 6142     (flush _test-output-buffered-file)
 6143     (flush _test-error-buffered-file)
 6144 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6150     # check output
 6151     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-few-inouts: output should be empty")
 6152     (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")
 6153     # check that stop(1) was called
 6154     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-few-inouts: exit status")
 6155     # don't restore from ebp
 6156     81 0/subop/add %esp 8/imm32
 6157     # . epilogue
 6158     5d/pop-to-ebp
 6159     c3/return
 6160 
 6161 test-get-with-too-many-inouts:
 6162     # . prologue
 6163     55/push-ebp
 6164     89/<- %ebp 4/r32/esp
 6165     # setup
 6166     (clear-stream _test-input-stream)
 6167     (clear-stream $_test-input-buffered-file->buffer)
 6168     (clear-stream _test-output-stream)
 6169     (clear-stream $_test-output-buffered-file->buffer)
 6170     (clear-stream _test-error-stream)
 6171     (clear-stream $_test-error-buffered-file->buffer)
 6172     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6173     68/push 0/imm32
 6174     68/push 0/imm32
 6175     89/<- %edx 4/r32/esp
 6176     (tailor-exit-descriptor %edx 0x10)
 6177     #
 6178     (write _test-input-stream "fn foo {\n")
 6179     (write _test-input-stream "  var a: t\n")
 6180     (write _test-input-stream "  var c/ecx: (addr int) <- get a, x, 0\n")
 6181     (write _test-input-stream "}\n")
 6182     (write _test-input-stream "type t {\n")
 6183     (write _test-input-stream "  x: int\n")
 6184     (write _test-input-stream "}\n")
 6185     # convert
 6186     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6187     # registers except esp clobbered at this point
 6188     # restore ed
 6189     89/<- %edx 4/r32/esp
 6190     (flush _test-output-buffered-file)
 6191     (flush _test-error-buffered-file)
 6192 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6198     # check output
 6199     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-many-inouts: output should be empty")
 6200     (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")
 6201     # check that stop(1) was called
 6202     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-many-inouts: exit status")
 6203     # don't restore from ebp
 6204     81 0/subop/add %esp 8/imm32
 6205     # . epilogue
 6206     5d/pop-to-ebp
 6207     c3/return
 6208 
 6209 test-get-with-no-output:
 6210     # . prologue
 6211     55/push-ebp
 6212     89/<- %ebp 4/r32/esp
 6213     # setup
 6214     (clear-stream _test-input-stream)
 6215     (clear-stream $_test-input-buffered-file->buffer)
 6216     (clear-stream _test-output-stream)
 6217     (clear-stream $_test-output-buffered-file->buffer)
 6218     (clear-stream _test-error-stream)
 6219     (clear-stream $_test-error-buffered-file->buffer)
 6220     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6221     68/push 0/imm32
 6222     68/push 0/imm32
 6223     89/<- %edx 4/r32/esp
 6224     (tailor-exit-descriptor %edx 0x10)
 6225     #
 6226     (write _test-input-stream "fn foo {\n")
 6227     (write _test-input-stream "  var a: t\n")
 6228     (write _test-input-stream "  get a, x\n")
 6229     (write _test-input-stream "}\n")
 6230     (write _test-input-stream "type t {\n")
 6231     (write _test-input-stream "  x: int\n")
 6232     (write _test-input-stream "}\n")
 6233     # convert
 6234     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6235     # registers except esp clobbered at this point
 6236     # restore ed
 6237     89/<- %edx 4/r32/esp
 6238     (flush _test-output-buffered-file)
 6239     (flush _test-error-buffered-file)
 6240 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6246     # check output
 6247     (check-stream-equal _test-output-stream  ""  "F - test-get-with-no-output: output should be empty")
 6248     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: must have an output"  "F - test-get-with-no-output: error message")
 6249     # check that stop(1) was called
 6250     (check-ints-equal *(edx+4) 2 "F - test-get-with-no-output: exit status")
 6251     # don't restore from ebp
 6252     81 0/subop/add %esp 8/imm32
 6253     # . epilogue
 6254     5d/pop-to-ebp
 6255     c3/return
 6256 
 6257 test-get-with-too-many-outputs:
 6258     # . prologue
 6259     55/push-ebp
 6260     89/<- %ebp 4/r32/esp
 6261     # setup
 6262     (clear-stream _test-input-stream)
 6263     (clear-stream $_test-input-buffered-file->buffer)
 6264     (clear-stream _test-output-stream)
 6265     (clear-stream $_test-output-buffered-file->buffer)
 6266     (clear-stream _test-error-stream)
 6267     (clear-stream $_test-error-buffered-file->buffer)
 6268     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6269     68/push 0/imm32
 6270     68/push 0/imm32
 6271     89/<- %edx 4/r32/esp
 6272     (tailor-exit-descriptor %edx 0x10)
 6273     #
 6274     (write _test-input-stream "fn foo {\n")
 6275     (write _test-input-stream "  var a: t\n")
 6276     (write _test-input-stream "  var b: int\n")
 6277     (write _test-input-stream "  var c/eax: (addr int) <- copy 0\n")
 6278     (write _test-input-stream "  c, b <- get a, x\n")
 6279     (write _test-input-stream "}\n")
 6280     (write _test-input-stream "type t {\n")
 6281     (write _test-input-stream "  x: int\n")
 6282     (write _test-input-stream "}\n")
 6283     # convert
 6284     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6285     # registers except esp clobbered at this point
 6286     # restore ed
 6287     89/<- %edx 4/r32/esp
 6288     (flush _test-output-buffered-file)
 6289     (flush _test-error-buffered-file)
 6290 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6296     # check output
 6297     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-many-outputs: output should be empty")
 6298     (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")
 6299     # check that stop(1) was called
 6300     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-many-outputs: exit status")
 6301     # don't restore from ebp
 6302     81 0/subop/add %esp 8/imm32
 6303     # . epilogue
 6304     5d/pop-to-ebp
 6305     c3/return
 6306 
 6307 test-convert-array-of-user-defined-types:
 6308     # . prologue
 6309     55/push-ebp
 6310     89/<- %ebp 4/r32/esp
 6311     # setup
 6312     (clear-stream _test-input-stream)
 6313     (clear-stream $_test-input-buffered-file->buffer)
 6314     (clear-stream _test-output-stream)
 6315     (clear-stream $_test-output-buffered-file->buffer)
 6316     #
 6317     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
 6318     (write _test-input-stream "  x: int\n")
 6319     (write _test-input-stream "  y: int\n")
 6320     (write _test-input-stream "}\n")
 6321     (write _test-input-stream "fn foo {\n")
 6322     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6323     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 6324     (write _test-input-stream "  var x/eax: (addr t) <- index arr, idx\n")
 6325     (write _test-input-stream "}\n")
 6326     # convert
 6327     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6328     (flush _test-output-buffered-file)
 6329 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 6335     # check output
 6336     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-array-of-user-defined-types/0")
 6337     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-array-of-user-defined-types/1")
 6338     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-array-of-user-defined-types/2")
 6339     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-array-of-user-defined-types/3")
 6340     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-array-of-user-defined-types/4")
 6341     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-array-of-user-defined-types/5")
 6342     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-array-of-user-defined-types/6")
 6343     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-array-of-user-defined-types/7")
 6344     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-array-of-user-defined-types/8")
 6345     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-array-of-user-defined-types/9")
 6346     (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")
 6347     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-array-of-user-defined-types/13")
 6348     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-array-of-user-defined-types/14")
 6349     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-array-of-user-defined-types/15")
 6350     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-array-of-user-defined-types/16")
 6351     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-array-of-user-defined-types/17")
 6352     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-array-of-user-defined-types/18")
 6353     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-array-of-user-defined-types/19")
 6354     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-array-of-user-defined-types/20")
 6355     # . epilogue
 6356     89/<- %esp 5/r32/ebp
 6357     5d/pop-to-ebp
 6358     c3/return
 6359 
 6360 test-convert-length-of-array-of-user-defined-types-to-eax:
 6361     # . prologue
 6362     55/push-ebp
 6363     89/<- %ebp 4/r32/esp
 6364     # setup
 6365     (clear-stream _test-input-stream)
 6366     (clear-stream $_test-input-buffered-file->buffer)
 6367     (clear-stream _test-output-stream)
 6368     (clear-stream $_test-output-buffered-file->buffer)
 6369     #
 6370     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 6371     (write _test-input-stream "  x: int\n")
 6372     (write _test-input-stream "  y: int\n")
 6373     (write _test-input-stream "  z: int\n")
 6374     (write _test-input-stream "}\n")
 6375     (write _test-input-stream "fn foo {\n")
 6376     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6377     (write _test-input-stream "  var x/eax: (addr t) <- length arr\n")
 6378     (write _test-input-stream "}\n")
 6379     # convert
 6380     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6381     (flush _test-output-buffered-file)
 6382 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 6388     # check output
 6389     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-eax/0")
 6390     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/1")
 6391     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-eax/2")
 6392     (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")
 6393     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/4")
 6394     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-eax/5")
 6395     # var arr
 6396     (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")
 6397     (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")
 6398     # length instruction
 6399     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/8")
 6400     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/9")
 6401     (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")
 6402     (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")
 6403     (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")
 6404     (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")
 6405     (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")
 6406     (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")
 6407     # reclaim arr
 6408     (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")
 6409     #
 6410     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/17")
 6411     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/18")
 6412     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/19")
 6413     (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")
 6414     (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")
 6415     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-eax/22")
 6416     # . epilogue
 6417     89/<- %esp 5/r32/ebp
 6418     5d/pop-to-ebp
 6419     c3/return
 6420 
 6421 test-convert-length-of-array-of-user-defined-types-to-ecx:
 6422     # . prologue
 6423     55/push-ebp
 6424     89/<- %ebp 4/r32/esp
 6425     # setup
 6426     (clear-stream _test-input-stream)
 6427     (clear-stream $_test-input-buffered-file->buffer)
 6428     (clear-stream _test-output-stream)
 6429     (clear-stream $_test-output-buffered-file->buffer)
 6430     #
 6431     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 6432     (write _test-input-stream "  x: int\n")
 6433     (write _test-input-stream "  y: int\n")
 6434     (write _test-input-stream "  z: int\n")
 6435     (write _test-input-stream "}\n")
 6436     (write _test-input-stream "fn foo {\n")
 6437     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6438     (write _test-input-stream "  var x/ecx: (addr t) <- length arr\n")
 6439     (write _test-input-stream "}\n")
 6440     # convert
 6441     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6442     (flush _test-output-buffered-file)
 6443 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 6449     # check output
 6450     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-ecx/0")
 6451     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/1")
 6452     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-ecx/2")
 6453     (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")
 6454     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/4")
 6455     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-ecx/5")
 6456     # var a
 6457     (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")
 6458     (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")
 6459     # var x
 6460     (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")
 6461     # length instruction
 6462     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/9")
 6463     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/10")
 6464     (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")
 6465     (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")
 6466     (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")
 6467     (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")
 6468     (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")
 6469     (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")
 6470     (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")
 6471     # reclaim x
 6472     (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")
 6473     # reclaim a
 6474     (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")
 6475     #
 6476     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/20")
 6477     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/21")
 6478     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/22")
 6479     (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")
 6480     (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")
 6481     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-ecx/25")
 6482     # . epilogue
 6483     89/<- %esp 5/r32/ebp
 6484     5d/pop-to-ebp
 6485     c3/return
 6486 
 6487 test-convert-length-of-array-of-user-defined-types-to-edx:
 6488     # . prologue
 6489     55/push-ebp
 6490     89/<- %ebp 4/r32/esp
 6491     # setup
 6492     (clear-stream _test-input-stream)
 6493     (clear-stream $_test-input-buffered-file->buffer)
 6494     (clear-stream _test-output-stream)
 6495     (clear-stream $_test-output-buffered-file->buffer)
 6496     #
 6497     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 6498     (write _test-input-stream "  x: int\n")
 6499     (write _test-input-stream "  y: int\n")
 6500     (write _test-input-stream "  z: int\n")
 6501     (write _test-input-stream "}\n")
 6502     (write _test-input-stream "fn foo {\n")
 6503     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6504     (write _test-input-stream "  var x/edx: (addr t) <- length arr\n")
 6505     (write _test-input-stream "}\n")
 6506     # convert
 6507     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6508     (flush _test-output-buffered-file)
 6509 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 6515     # check output
 6516     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-edx/0")
 6517     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/1")
 6518     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-edx/2")
 6519     (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")
 6520     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/4")
 6521     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-edx/5")
 6522     # var a
 6523     (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")
 6524     (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")
 6525     # var x
 6526     (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")
 6527     # length instruction
 6528     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/9")
 6529     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/10")
 6530     (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")
 6531     (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")
 6532     (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")
 6533     (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")
 6534     (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")
 6535     (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")
 6536     (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")
 6537     # reclaim x
 6538     (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")
 6539     # reclaim a
 6540     (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")
 6541     #
 6542     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/20")
 6543     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/21")
 6544     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/22")
 6545     (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")
 6546     (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")
 6547     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-edx/25")
 6548     # . epilogue
 6549     89/<- %esp 5/r32/ebp
 6550     5d/pop-to-ebp
 6551     c3/return
 6552 
 6553 test-convert-length-of-array-of-user-defined-types:
 6554     # . prologue
 6555     55/push-ebp
 6556     89/<- %ebp 4/r32/esp
 6557     # setup
 6558     (clear-stream _test-input-stream)
 6559     (clear-stream $_test-input-buffered-file->buffer)
 6560     (clear-stream _test-output-stream)
 6561     (clear-stream $_test-output-buffered-file->buffer)
 6562     #
 6563     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
 6564     (write _test-input-stream "  x: int\n")
 6565     (write _test-input-stream "  y: int\n")
 6566     (write _test-input-stream "  z: int\n")
 6567     (write _test-input-stream "}\n")
 6568     (write _test-input-stream "fn foo {\n")
 6569     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6570     (write _test-input-stream "  var x/ebx: (addr t) <- length arr\n")
 6571     (write _test-input-stream "}\n")
 6572     # convert
 6573     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6574     (flush _test-output-buffered-file)
 6575 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 6581     # check output
 6582     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types/0")
 6583     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types/1")
 6584     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types/2")
 6585     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-user-defined-types/3")
 6586     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types/4")
 6587     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types/5")
 6588     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-user-defined-types/6")
 6589     (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")
 6590     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ebx"  "F - test-convert-length-of-array-of-user-defined-types/8")
 6591     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types/9")
 6592     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types/10")
 6593     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types/11")
 6594     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-user-defined-types/12")
 6595     (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")
 6596     (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")
 6597     (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")
 6598     (check-next-stream-line-equal _test-output-stream "    89/<- %ebx 0/r32/eax"  "F - test-convert-length-of-array-of-user-defined-types/16")
 6599     (check-next-stream-line-equal _test-output-stream "    5a/pop-to-edx"       "F - test-convert-length-of-array-of-user-defined-types/17")
 6600     (check-next-stream-line-equal _test-output-stream "    59/pop-to-ecx"       "F - test-convert-length-of-array-of-user-defined-types/18")
 6601     (check-next-stream-line-equal _test-output-stream "    58/pop-to-eax"       "F - test-convert-length-of-array-of-user-defined-types/19")
 6602     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ebx"  "F - test-convert-length-of-array-of-user-defined-types/20")
 6603     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-user-defined-types/21")
 6604     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types/22")
 6605     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types/23")
 6606     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types/24")
 6607     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-user-defined-types/25")
 6608     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-user-defined-types/26")
 6609     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types/27")
 6610     # . epilogue
 6611     89/<- %esp 5/r32/ebp
 6612     5d/pop-to-ebp
 6613     c3/return
 6614 
 6615 test-index-with-non-array-atom-base-type:
 6616     # . prologue
 6617     55/push-ebp
 6618     89/<- %ebp 4/r32/esp
 6619     # setup
 6620     (clear-stream _test-input-stream)
 6621     (clear-stream $_test-input-buffered-file->buffer)
 6622     (clear-stream _test-output-stream)
 6623     (clear-stream $_test-output-buffered-file->buffer)
 6624     (clear-stream _test-error-stream)
 6625     (clear-stream $_test-error-buffered-file->buffer)
 6626     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6627     68/push 0/imm32
 6628     68/push 0/imm32
 6629     89/<- %edx 4/r32/esp
 6630     (tailor-exit-descriptor %edx 0x10)
 6631     #
 6632     (write _test-input-stream "fn foo {\n")
 6633     (write _test-input-stream "  var a: int\n")
 6634     (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
 6635     (write _test-input-stream "}\n")
 6636     # convert
 6637     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6638     # registers except esp clobbered at this point
 6639     # restore ed
 6640     89/<- %edx 4/r32/esp
 6641     (flush _test-output-buffered-file)
 6642     (flush _test-error-buffered-file)
 6643 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6649     # check output
 6650     (check-stream-equal _test-output-stream  ""  "F - test-index-with-non-array-atom-base-type: output should be empty")
 6651     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: var 'a' is not an array"  "F - test-index-with-non-array-atom-base-type: error message")
 6652     # check that stop(1) was called
 6653     (check-ints-equal *(edx+4) 2 "F - test-index-with-non-array-atom-base-type: exit status")
 6654     # don't restore from ebp
 6655     81 0/subop/add %esp 8/imm32
 6656     # . epilogue
 6657     5d/pop-to-ebp
 6658     c3/return
 6659 
 6660 test-index-with-non-array-compound-base-type:
 6661     # . prologue
 6662     55/push-ebp
 6663     89/<- %ebp 4/r32/esp
 6664     # setup
 6665     (clear-stream _test-input-stream)
 6666     (clear-stream $_test-input-buffered-file->buffer)
 6667     (clear-stream _test-output-stream)
 6668     (clear-stream $_test-output-buffered-file->buffer)
 6669     (clear-stream _test-error-stream)
 6670     (clear-stream $_test-error-buffered-file->buffer)
 6671     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6672     68/push 0/imm32
 6673     68/push 0/imm32
 6674     89/<- %edx 4/r32/esp
 6675     (tailor-exit-descriptor %edx 0x10)
 6676     #
 6677     (write _test-input-stream "fn foo {\n")
 6678     (write _test-input-stream "  var a: (handle int)\n")
 6679     (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
 6680     (write _test-input-stream "}\n")
 6681     # convert
 6682     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6683     # registers except esp clobbered at this point
 6684     # restore ed
 6685     89/<- %edx 4/r32/esp
 6686     (flush _test-output-buffered-file)
 6687     (flush _test-error-buffered-file)
 6688 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6694     # check output
 6695     (check-stream-equal _test-output-stream  ""  "F - test-index-with-non-array-compound-base-type: output should be empty")
 6696     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: var 'a' is not an array"  "F - test-index-with-non-array-compound-base-type: error message")
 6697     # check that stop(1) was called
 6698     (check-ints-equal *(edx+4) 2 "F - test-index-with-non-array-compound-base-type: exit status")
 6699     # don't restore from ebp
 6700     81 0/subop/add %esp 8/imm32
 6701     # . epilogue
 6702     5d/pop-to-ebp
 6703     c3/return
 6704 
 6705 test-index-with-non-array-compound-base-type-2:
 6706     # . prologue
 6707     55/push-ebp
 6708     89/<- %ebp 4/r32/esp
 6709     # setup
 6710     (clear-stream _test-input-stream)
 6711     (clear-stream $_test-input-buffered-file->buffer)
 6712     (clear-stream _test-output-stream)
 6713     (clear-stream $_test-output-buffered-file->buffer)
 6714     (clear-stream _test-error-stream)
 6715     (clear-stream $_test-error-buffered-file->buffer)
 6716     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6717     68/push 0/imm32
 6718     68/push 0/imm32
 6719     89/<- %edx 4/r32/esp
 6720     (tailor-exit-descriptor %edx 0x10)
 6721     #
 6722     (write _test-input-stream "fn foo {\n")
 6723     (write _test-input-stream "  var a: (addr int)\n")
 6724     (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
 6725     (write _test-input-stream "}\n")
 6726     # convert
 6727     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6728     # registers except esp clobbered at this point
 6729     # restore ed
 6730     89/<- %edx 4/r32/esp
 6731     (flush _test-output-buffered-file)
 6732     (flush _test-error-buffered-file)
 6733 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6739     # check output
 6740     (check-stream-equal _test-output-stream  ""  "F - test-index-with-non-array-compound-base-type-2: output should be empty")
 6741     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: var 'a' is not an array"  "F - test-index-with-non-array-compound-base-type-2: error message")
 6742     # check that stop(1) was called
 6743     (check-ints-equal *(edx+4) 2 "F - test-index-with-non-array-compound-base-type-2: exit status")
 6744     # don't restore from ebp
 6745     81 0/subop/add %esp 8/imm32
 6746     # . epilogue
 6747     5d/pop-to-ebp
 6748     c3/return
 6749 
 6750 test-index-with-array-atom-base-type:
 6751     # . prologue
 6752     55/push-ebp
 6753     89/<- %ebp 4/r32/esp
 6754     # setup
 6755     (clear-stream _test-input-stream)
 6756     (clear-stream $_test-input-buffered-file->buffer)
 6757     (clear-stream _test-output-stream)
 6758     (clear-stream $_test-output-buffered-file->buffer)
 6759     (clear-stream _test-error-stream)
 6760     (clear-stream $_test-error-buffered-file->buffer)
 6761     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6762     68/push 0/imm32
 6763     68/push 0/imm32
 6764     89/<- %edx 4/r32/esp
 6765     (tailor-exit-descriptor %edx 0x10)
 6766     #
 6767     (write _test-input-stream "fn foo {\n")
 6768     (write _test-input-stream "  var a: array\n")
 6769     (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
 6770     (write _test-input-stream "}\n")
 6771     # convert
 6772     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6773     # registers except esp clobbered at this point
 6774     # restore ed
 6775     89/<- %edx 4/r32/esp
 6776     (flush _test-output-buffered-file)
 6777     (flush _test-error-buffered-file)
 6778 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6784     # check output
 6785     (check-stream-equal _test-output-stream  ""  "F - test-index-with-array-atom-base-type: output should be empty")
 6786     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: array 'a' must specify the type of its elements"  "F - test-index-with-array-atom-base-type: error message")
 6787     # check that stop(1) was called
 6788     (check-ints-equal *(edx+4) 2 "F - test-index-with-array-atom-base-type: exit status")
 6789     # don't restore from ebp
 6790     81 0/subop/add %esp 8/imm32
 6791     # . epilogue
 6792     5d/pop-to-ebp
 6793     c3/return
 6794 
 6795 test-index-with-addr-base-on-stack:
 6796     # . prologue
 6797     55/push-ebp
 6798     89/<- %ebp 4/r32/esp
 6799     # setup
 6800     (clear-stream _test-input-stream)
 6801     (clear-stream $_test-input-buffered-file->buffer)
 6802     (clear-stream _test-output-stream)
 6803     (clear-stream $_test-output-buffered-file->buffer)
 6804     (clear-stream _test-error-stream)
 6805     (clear-stream $_test-error-buffered-file->buffer)
 6806     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6807     68/push 0/imm32
 6808     68/push 0/imm32
 6809     89/<- %edx 4/r32/esp
 6810     (tailor-exit-descriptor %edx 0x10)
 6811     #
 6812     (write _test-input-stream "fn foo {\n")
 6813     (write _test-input-stream "  var a: (addr array int)\n")
 6814     (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
 6815     (write _test-input-stream "}\n")
 6816     # convert
 6817     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6818     # registers except esp clobbered at this point
 6819     # restore ed
 6820     89/<- %edx 4/r32/esp
 6821     (flush _test-output-buffered-file)
 6822     (flush _test-error-buffered-file)
 6823 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6829     # check output
 6830     (check-stream-equal _test-output-stream  ""  "F - test-index-with-addr-base-on-stack: output should be empty")
 6831     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: var 'a' is an addr to an array, and so must live in a register"  "F - test-index-with-addr-base-on-stack: error message")
 6832     # check that stop(1) was called
 6833     (check-ints-equal *(edx+4) 2 "F - test-index-with-addr-base-on-stack: exit status")
 6834     # don't restore from ebp
 6835     81 0/subop/add %esp 8/imm32
 6836     # . epilogue
 6837     5d/pop-to-ebp
 6838     c3/return
 6839 
 6840 test-index-with-array-base-in-register:
 6841     # . prologue
 6842     55/push-ebp
 6843     89/<- %ebp 4/r32/esp
 6844     # setup
 6845     (clear-stream _test-input-stream)
 6846     (clear-stream $_test-input-buffered-file->buffer)
 6847     (clear-stream _test-output-stream)
 6848     (clear-stream $_test-output-buffered-file->buffer)
 6849     (clear-stream _test-error-stream)
 6850     (clear-stream $_test-error-buffered-file->buffer)
 6851     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6852     68/push 0/imm32
 6853     68/push 0/imm32
 6854     89/<- %edx 4/r32/esp
 6855     (tailor-exit-descriptor %edx 0x10)
 6856     #
 6857     (write _test-input-stream "fn foo {\n")
 6858     (write _test-input-stream "  var a/eax: (array int 3) <- copy 0\n")
 6859     (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
 6860     (write _test-input-stream "}\n")
 6861     # convert
 6862     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6863     # registers except esp clobbered at this point
 6864     # restore ed
 6865     89/<- %edx 4/r32/esp
 6866     (flush _test-output-buffered-file)
 6867     (flush _test-error-buffered-file)
 6868 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6874     # check output
 6875     (check-stream-equal _test-output-stream  ""  "F - test-index-with-array-base-in-register: output should be empty")
 6876     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: var 'a' is an array, and so must live on the stack"  "F - test-index-with-array-base-in-register: error message")
 6877     # check that stop(1) was called
 6878     (check-ints-equal *(edx+4) 2 "F - test-index-with-array-base-in-register: exit status")
 6879     # don't restore from ebp
 6880     81 0/subop/add %esp 8/imm32
 6881     # . epilogue
 6882     5d/pop-to-ebp
 6883     c3/return
 6884 
 6885 test-index-with-wrong-index-type:
 6886     # . prologue
 6887     55/push-ebp
 6888     89/<- %ebp 4/r32/esp
 6889     # setup
 6890     (clear-stream _test-input-stream)
 6891     (clear-stream $_test-input-buffered-file->buffer)
 6892     (clear-stream _test-output-stream)
 6893     (clear-stream $_test-output-buffered-file->buffer)
 6894     (clear-stream _test-error-stream)
 6895     (clear-stream $_test-error-buffered-file->buffer)
 6896     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6897     68/push 0/imm32
 6898     68/push 0/imm32
 6899     89/<- %edx 4/r32/esp
 6900     (tailor-exit-descriptor %edx 0x10)
 6901     #
 6902     (write _test-input-stream "fn foo {\n")
 6903     (write _test-input-stream "  var a/eax: (addr array int) <- copy 0\n")
 6904     (write _test-input-stream "  var b: boolean\n")
 6905     (write _test-input-stream "  var c/ecx: (addr int) <- index a, b\n")
 6906     (write _test-input-stream "}\n")
 6907     # convert
 6908     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6909     # registers except esp clobbered at this point
 6910     # restore ed
 6911     89/<- %edx 4/r32/esp
 6912     (flush _test-output-buffered-file)
 6913     (flush _test-error-buffered-file)
 6914 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6920     # check output
 6921     (check-stream-equal _test-output-stream  ""  "F - test-index-with-wrong-index-type: output should be empty")
 6922     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: second argument 'b' must be an int or offset"  "F - test-index-with-wrong-index-type: error message")
 6923     # check that stop(1) was called
 6924     (check-ints-equal *(edx+4) 2 "F - test-index-with-wrong-index-type: exit status")
 6925     # don't restore from ebp
 6926     81 0/subop/add %esp 8/imm32
 6927     # . epilogue
 6928     5d/pop-to-ebp
 6929     c3/return
 6930 
 6931 test-index-with-offset-atom-index-type:
 6932     # . prologue
 6933     55/push-ebp
 6934     89/<- %ebp 4/r32/esp
 6935     # setup
 6936     (clear-stream _test-input-stream)
 6937     (clear-stream $_test-input-buffered-file->buffer)
 6938     (clear-stream _test-output-stream)
 6939     (clear-stream $_test-output-buffered-file->buffer)
 6940     (clear-stream _test-error-stream)
 6941     (clear-stream $_test-error-buffered-file->buffer)
 6942     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6943     68/push 0/imm32
 6944     68/push 0/imm32
 6945     89/<- %edx 4/r32/esp
 6946     (tailor-exit-descriptor %edx 0x10)
 6947     #
 6948     (write _test-input-stream "fn foo {\n")
 6949     (write _test-input-stream "  var a/eax: (addr array int) <- copy 0\n")
 6950     (write _test-input-stream "  var b: offset\n")
 6951     (write _test-input-stream "  var c/ecx: (addr int) <- index a, b\n")
 6952     (write _test-input-stream "}\n")
 6953     # convert
 6954     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6955     # registers except esp clobbered at this point
 6956     # restore ed
 6957     89/<- %edx 4/r32/esp
 6958     (flush _test-output-buffered-file)
 6959     (flush _test-error-buffered-file)
 6960 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 6966     # check output
 6967     (check-stream-equal _test-output-stream  ""  "F - test-index-with-offset-atom-index-type: output should be empty")
 6968     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: offset 'b' must specify the type of array elements"  "F - test-index-with-offset-atom-index-type: error message")
 6969     # check that stop(1) was called
 6970     (check-ints-equal *(edx+4) 2 "F - test-index-with-offset-atom-index-type: exit status")
 6971     # don't restore from ebp
 6972     81 0/subop/add %esp 8/imm32
 6973     # . epilogue
 6974     5d/pop-to-ebp
 6975     c3/return
 6976 
 6977 test-index-with-offset-on-stack:
 6978     # . prologue
 6979     55/push-ebp
 6980     89/<- %ebp 4/r32/esp
 6981     # setup
 6982     (clear-stream _test-input-stream)
 6983     (clear-stream $_test-input-buffered-file->buffer)
 6984     (clear-stream _test-output-stream)
 6985     (clear-stream $_test-output-buffered-file->buffer)
 6986     (clear-stream _test-error-stream)
 6987     (clear-stream $_test-error-buffered-file->buffer)
 6988     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6989     68/push 0/imm32
 6990     68/push 0/imm32
 6991     89/<- %edx 4/r32/esp
 6992     (tailor-exit-descriptor %edx 0x10)
 6993     #
 6994     (write _test-input-stream "fn foo {\n")
 6995     (write _test-input-stream "  var a/eax: (addr array int) <- copy 0\n")
 6996     (write _test-input-stream "  var b: int\n")
 6997     (write _test-input-stream "  var c/ecx: (addr int) <- index a, b\n")
 6998     (write _test-input-stream "}\n")
 6999     # convert
 7000     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7001     # registers except esp clobbered at this point
 7002     # restore ed
 7003     89/<- %edx 4/r32/esp
 7004     (flush _test-output-buffered-file)
 7005     (flush _test-error-buffered-file)
 7006 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 7012     # check output
 7013     (check-stream-equal _test-output-stream  ""  "F - test-index-with-offset-on-stack: output should be empty")
 7014     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: second argument 'b' must be in a register"  "F - test-index-with-offset-on-stack: error message")
 7015     # check that stop(1) was called
 7016     (check-ints-equal *(edx+4) 2 "F - test-index-with-offset-on-stack: exit status")
 7017     # don't restore from ebp
 7018     81 0/subop/add %esp 8/imm32
 7019     # . epilogue
 7020     5d/pop-to-ebp
 7021     c3/return
 7022 
 7023 test-index-needs-offset-type:
 7024     # . prologue
 7025     55/push-ebp
 7026     89/<- %ebp 4/r32/esp
 7027     # setup
 7028     (clear-stream _test-input-stream)
 7029     (clear-stream $_test-input-buffered-file->buffer)
 7030     (clear-stream _test-output-stream)
 7031     (clear-stream $_test-output-buffered-file->buffer)
 7032     (clear-stream _test-error-stream)
 7033     (clear-stream $_test-error-buffered-file->buffer)
 7034     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7035     68/push 0/imm32
 7036     68/push 0/imm32
 7037     89/<- %edx 4/r32/esp
 7038     (tailor-exit-descriptor %edx 0x10)
 7039     #
 7040     (write _test-input-stream "fn foo {\n")
 7041     (write _test-input-stream "  var a/eax: (addr array t) <- copy 0\n")
 7042     (write _test-input-stream "  var b/ebx: int <- copy 0\n")
 7043     (write _test-input-stream "  var c/ecx: (addr int) <- index a, b\n")
 7044     (write _test-input-stream "}\n")
 7045     (write _test-input-stream "type t {\n")  # size 12 is not a power of two
 7046     (write _test-input-stream "  x: int\n")
 7047     (write _test-input-stream "  y: int\n")
 7048     (write _test-input-stream "  z: int\n")
 7049     (write _test-input-stream "}\n")
 7050     # convert
 7051     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7052     # registers except esp clobbered at this point
 7053     # restore ed
 7054     89/<- %edx 4/r32/esp
 7055     (flush _test-output-buffered-file)
 7056     (flush _test-error-buffered-file)
 7057 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 7063     # check output
 7064     (check-stream-equal _test-output-stream  ""  "F - test-index-needs-offset-type: output should be empty")
 7065     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: cannot take an int for array 'a'; create an offset instead. See mu_summary for details."  "F - test-index-needs-offset-type: error message")
 7066     # check that stop(1) was called
 7067     (check-ints-equal *(edx+4) 2 "F - test-index-needs-offset-type: exit status")
 7068     # don't restore from ebp
 7069     81 0/subop/add %esp 8/imm32
 7070     # . epilogue
 7071     5d/pop-to-ebp
 7072     c3/return
 7073 
 7074 test-index-with-output-not-address:
 7075     # . prologue
 7076     55/push-ebp
 7077     89/<- %ebp 4/r32/esp
 7078     # setup
 7079     (clear-stream _test-input-stream)
 7080     (clear-stream $_test-input-buffered-file->buffer)
 7081     (clear-stream _test-output-stream)
 7082     (clear-stream $_test-output-buffered-file->buffer)
 7083     (clear-stream _test-error-stream)
 7084     (clear-stream $_test-error-buffered-file->buffer)
 7085     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7086     68/push 0/imm32
 7087     68/push 0/imm32
 7088     89/<- %edx 4/r32/esp
 7089     (tailor-exit-descriptor %edx 0x10)
 7090     #
 7091     (write _test-input-stream "fn foo {\n")
 7092     (write _test-input-stream "  var a/ebx: (addr array boolean) <- copy 0\n")
 7093     (write _test-input-stream "  var o/edi: int <- index a, 0\n")
 7094     (write _test-input-stream "}\n")
 7095     # convert
 7096     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7097     # registers except esp clobbered at this point
 7098     # restore ed
 7099     89/<- %edx 4/r32/esp
 7100     (flush _test-output-buffered-file)
 7101     (flush _test-error-buffered-file)
 7102 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 7108     # check output
 7109     (check-stream-equal _test-output-stream  ""  "F - test-index-with-output-not-address: output should be empty")
 7110     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: output 'o' must be an address"  "F - test-index-with-output-not-address: error message")
 7111     # check that stop(1) was called
 7112     (check-ints-equal *(edx+4) 2 "F - test-index-with-output-not-address: exit status")
 7113     # don't restore from ebp
 7114     81 0/subop/add %esp 8/imm32
 7115     # . epilogue
 7116     5d/pop-to-ebp
 7117     c3/return
 7118 
 7119 test-index-with-output-not-address-2:
 7120     # . prologue
 7121     55/push-ebp
 7122     89/<- %ebp 4/r32/esp
 7123     # setup
 7124     (clear-stream _test-input-stream)
 7125     (clear-stream $_test-input-buffered-file->buffer)
 7126     (clear-stream _test-output-stream)
 7127     (clear-stream $_test-output-buffered-file->buffer)
 7128     (clear-stream _test-error-stream)
 7129     (clear-stream $_test-error-buffered-file->buffer)
 7130     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7131     68/push 0/imm32
 7132     68/push 0/imm32
 7133     89/<- %edx 4/r32/esp
 7134     (tailor-exit-descriptor %edx 0x10)
 7135     #
 7136     (write _test-input-stream "fn foo {\n")
 7137     (write _test-input-stream "  var a/ebx: (addr array boolean) <- copy 0\n")
 7138     (write _test-input-stream "  var o/edi: (int) <- index a, 0\n")
 7139     (write _test-input-stream "}\n")
 7140     # convert
 7141     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7142     # registers except esp clobbered at this point
 7143     # restore ed
 7144     89/<- %edx 4/r32/esp
 7145     (flush _test-output-buffered-file)
 7146     (flush _test-error-buffered-file)
 7147 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 7153     # check output
 7154     (check-stream-equal _test-output-stream  ""  "F - test-index-with-output-not-address-2: output should be empty")
 7155     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: output 'o' must be an address"  "F - test-index-with-output-not-address-2: error message")
 7156     # check that stop(1) was called
 7157     (check-ints-equal *(edx+4) 2 "F - test-index-with-output-not-address-2: exit status")
 7158     # don't restore from ebp
 7159     81 0/subop/add %esp 8/imm32
 7160     # . epilogue
 7161     5d/pop-to-ebp
 7162     c3/return
 7163 
 7164 test-index-with-wrong-output-type:
 7165     # . prologue
 7166     55/push-ebp
 7167     89/<- %ebp 4/r32/esp
 7168     # setup
 7169     (clear-stream _test-input-stream)
 7170     (clear-stream $_test-input-buffered-file->buffer)
 7171     (clear-stream _test-output-stream)
 7172     (clear-stream $_test-output-buffered-file->buffer)
 7173     (clear-stream _test-error-stream)
 7174     (clear-stream $_test-error-buffered-file->buffer)
 7175     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7176     68/push 0/imm32
 7177     68/push 0/imm32
 7178     89/<- %edx 4/r32/esp
 7179     (tailor-exit-descriptor %edx 0x10)
 7180     #
 7181     (write _test-input-stream "fn foo {\n")
 7182     (write _test-input-stream "  var a/ebx: (addr array boolean) <- copy 0\n")
 7183     (write _test-input-stream "  var o/edi: (addr int) <- index a, 0\n")
 7184     (write _test-input-stream "}\n")
 7185     # convert
 7186     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7187     # registers except esp clobbered at this point
 7188     # restore ed
 7189     89/<- %edx 4/r32/esp
 7190     (flush _test-output-buffered-file)
 7191     (flush _test-error-buffered-file)
 7192 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 7198     # check output
 7199     (check-stream-equal _test-output-stream  ""  "F - test-index-with-wrong-output-type: output should be empty")
 7200     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: output 'o' does not have the right type"  "F - test-index-with-wrong-output-type: error message")
 7201     # check that stop(1) was called
 7202     (check-ints-equal *(edx+4) 2 "F - test-index-with-wrong-output-type: exit status")
 7203     # don't restore from ebp
 7204     81 0/subop/add %esp 8/imm32
 7205     # . epilogue
 7206     5d/pop-to-ebp
 7207     c3/return
 7208 
 7209 test-index-with-wrong-output-compound-type:
 7210     # . prologue
 7211     55/push-ebp
 7212     89/<- %ebp 4/r32/esp
 7213     # setup
 7214     (clear-stream _test-input-stream)
 7215     (clear-stream $_test-input-buffered-file->buffer)
 7216     (clear-stream _test-output-stream)
 7217     (clear-stream $_test-output-buffered-file->buffer)
 7218     (clear-stream _test-error-stream)
 7219     (clear-stream $_test-error-buffered-file->buffer)
 7220     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7221     68/push 0/imm32
 7222     68/push 0/imm32
 7223     89/<- %edx 4/r32/esp
 7224     (tailor-exit-descriptor %edx 0x10)
 7225     #
 7226     (write _test-input-stream "fn foo {\n")
 7227     (write _test-input-stream "  var a/ebx: (addr array handle boolean) <- copy 0\n")
 7228     (write _test-input-stream "  var o/edi: (addr handle int) <- index a, 0\n")
 7229     (write _test-input-stream "}\n")
 7230     # convert
 7231     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7232     # registers except esp clobbered at this point
 7233     # restore ed
 7234     89/<- %edx 4/r32/esp
 7235     (flush _test-output-buffered-file)
 7236     (flush _test-error-buffered-file)
 7237 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 7243     # check output
 7244     (check-stream-equal _test-output-stream  ""  "F - test-index-with-wrong-output-compound-type: output should be empty")
 7245     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: output 'o' does not have the right type"  "F - test-index-with-wrong-output-compound-type: error message")
 7246     # check that stop(1) was called
 7247     (check-ints-equal *(edx+4) 2 "F - test-index-with-wrong-output-compound-type: exit status")
 7248     # don't restore from ebp
 7249     81 0/subop/add %esp 8/imm32
 7250     # . epilogue
 7251     5d/pop-to-ebp
 7252     c3/return
 7253 
 7254 test-index-with-no-inouts:
 7255     # . prologue
 7256     55/push-ebp
 7257     89/<- %ebp 4/r32/esp
 7258     # setup
 7259     (clear-stream _test-input-stream)
 7260     (clear-stream $_test-input-buffered-file->buffer)
 7261     (clear-stream _test-output-stream)
 7262     (clear-stream $_test-output-buffered-file->buffer)
 7263     (clear-stream _test-error-stream)
 7264     (clear-stream $_test-error-buffered-file->buffer)
 7265     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7266     68/push 0/imm32
 7267     68/push 0/imm32
 7268     89/<- %edx 4/r32/esp
 7269     (tailor-exit-descriptor %edx 0x10)
 7270     #
 7271     (write _test-input-stream "fn foo {\n")
 7272     (write _test-input-stream "  var c/ecx: (addr int) <- index\n")
 7273     (write _test-input-stream "}\n")
 7274     # convert
 7275     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7276     # registers except esp clobbered at this point
 7277     # restore ed
 7278     89/<- %edx 4/r32/esp
 7279     (flush _test-output-buffered-file)
 7280     (flush _test-error-buffered-file)
 7281 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 7287     # check output
 7288     (check-stream-equal _test-output-stream  ""  "F - test-index-with-no-inouts: output should be empty")
 7289     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: too few inouts (2 required)"  "F - test-index-with-no-inouts: error message")
 7290     # check that stop(1) was called
 7291     (check-ints-equal *(edx+4) 2 "F - test-index-with-no-inouts: exit status")
 7292     # don't restore from ebp
 7293     81 0/subop/add %esp 8/imm32
 7294     # . epilogue
 7295     5d/pop-to-ebp
 7296     c3/return
 7297 
 7298 test-index-with-too-few-inouts:
 7299     # . prologue
 7300     55/push-ebp
 7301     89/<- %ebp 4/r32/esp
 7302     # setup
 7303     (clear-stream _test-input-stream)
 7304     (clear-stream $_test-input-buffered-file->buffer)
 7305     (clear-stream _test-output-stream)
 7306     (clear-stream $_test-output-buffered-file->buffer)
 7307     (clear-stream _test-error-stream)
 7308     (clear-stream $_test-error-buffered-file->buffer)
 7309     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7310     68/push 0/imm32
 7311     68/push 0/imm32
 7312     89/<- %edx 4/r32/esp
 7313     (tailor-exit-descriptor %edx 0x10)
 7314     #
 7315     (write _test-input-stream "fn foo {\n")
 7316     (write _test-input-stream "  var a: (array int 3)\n")
 7317     (write _test-input-stream "  var c/ecx: (addr int) <- index a\n")
 7318     (write _test-input-stream "}\n")
 7319     # convert
 7320     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7321     # registers except esp clobbered at this point
 7322     # restore ed
 7323     89/<- %edx 4/r32/esp
 7324     (flush _test-output-buffered-file)
 7325     (flush _test-error-buffered-file)
 7326 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 7332     # check output
 7333     (check-stream-equal _test-output-stream  ""  "F - test-index-with-too-few-inouts: output should be empty")
 7334     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: too few inouts (2 required)"  "F - test-index-with-too-few-inouts: error message")
 7335     # check that stop(1) was called
 7336     (check-ints-equal *(edx+4) 2 "F - test-index-with-too-few-inouts: exit status")
 7337     # don't restore from ebp
 7338     81 0/subop/add %esp 8/imm32
 7339     # . epilogue
 7340     5d/pop-to-ebp
 7341     c3/return
 7342 
 7343 test-index-with-too-many-inouts:
 7344     # . prologue
 7345     55/push-ebp
 7346     89/<- %ebp 4/r32/esp
 7347     # setup
 7348     (clear-stream _test-input-stream)
 7349     (clear-stream $_test-input-buffered-file->buffer)
 7350     (clear-stream _test-output-stream)
 7351     (clear-stream $_test-output-buffered-file->buffer)
 7352     (clear-stream _test-error-stream)
 7353     (clear-stream $_test-error-buffered-file->buffer)
 7354     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7355     68/push 0/imm32
 7356     68/push 0/imm32
 7357     89/<- %edx 4/r32/esp
 7358     (tailor-exit-descriptor %edx 0x10)
 7359     #
 7360     (write _test-input-stream "fn foo {\n")
 7361     (write _test-input-stream "  var a: (array int 3)\n")
 7362     (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0, 0\n")
 7363     (write _test-input-stream "}\n")
 7364     # convert
 7365     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7366     # registers except esp clobbered at this point
 7367     # restore ed
 7368     89/<- %edx 4/r32/esp
 7369     (flush _test-output-buffered-file)
 7370     (flush _test-error-buffered-file)
 7371 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 7377     # check output
 7378     (check-stream-equal _test-output-stream  ""  "F - test-index-with-too-many-inouts: output should be empty")
 7379     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: too many inouts (2 required)"  "F - test-index-with-too-many-inouts: error message")
 7380     # check that stop(1) was called
 7381     (check-ints-equal *(edx+4) 2 "F - test-index-with-too-many-inouts: exit status")
 7382     # don't restore from ebp
 7383     81 0/subop/add %esp 8/imm32
 7384     # . epilogue
 7385     5d/pop-to-ebp
 7386     c3/return
 7387 
 7388 test-index-with-no-output:
 7389     # . prologue
 7390     55/push-ebp
 7391     89/<- %ebp 4/r32/esp
 7392     # setup
 7393     (clear-stream _test-input-stream)
 7394     (clear-stream $_test-input-buffered-file->buffer)
 7395     (clear-stream _test-output-stream)
 7396     (clear-stream $_test-output-buffered-file->buffer)
 7397     (clear-stream _test-error-stream)
 7398     (clear-stream $_test-error-buffered-file->buffer)
 7399     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7400     68/push 0/imm32
 7401     68/push 0/imm32
 7402     89/<- %edx 4/r32/esp
 7403     (tailor-exit-descriptor %edx 0x10)
 7404     #
 7405     (write _test-input-stream "fn foo {\n")
 7406     (write _test-input-stream "  var a: (array int 3)\n")
 7407     (write _test-input-stream "  index a, 0\n")
 7408     (write _test-input-stream "}\n")
 7409     # convert
 7410     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7411     # registers except esp clobbered at this point
 7412     # restore ed
 7413     89/<- %edx 4/r32/esp
 7414     (flush _test-output-buffered-file)
 7415     (flush _test-error-buffered-file)
 7416 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 7422     # check output
 7423     (check-stream-equal _test-output-stream  ""  "F - test-index-with-no-output: output should be empty")
 7424     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: must have an output"  "F - test-index-with-no-output: error message")
 7425     # check that stop(1) was called
 7426     (check-ints-equal *(edx+4) 2 "F - test-index-with-no-output: exit status")
 7427     # don't restore from ebp
 7428     81 0/subop/add %esp 8/imm32
 7429     # . epilogue
 7430     5d/pop-to-ebp
 7431     c3/return
 7432 
 7433 test-index-with-too-many-outputs:
 7434     # . prologue
 7435     55/push-ebp
 7436     89/<- %ebp 4/r32/esp
 7437     # setup
 7438     (clear-stream _test-input-stream)
 7439     (clear-stream $_test-input-buffered-file->buffer)
 7440     (clear-stream _test-output-stream)
 7441     (clear-stream $_test-output-buffered-file->buffer)
 7442     (clear-stream _test-error-stream)
 7443     (clear-stream $_test-error-buffered-file->buffer)
 7444     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7445     68/push 0/imm32
 7446     68/push 0/imm32
 7447     89/<- %edx 4/r32/esp
 7448     (tailor-exit-descriptor %edx 0x10)
 7449     #
 7450     (write _test-input-stream "fn foo {\n")
 7451     (write _test-input-stream "  var a: (array int 3)\n")
 7452     (write _test-input-stream "  var b/eax: (addr int) <- copy 0\n")
 7453     (write _test-input-stream "  var c/ecx: (addr int) <- copy 0\n")
 7454     (write _test-input-stream "  b, c <- index a, 0\n")
 7455     (write _test-input-stream "}\n")
 7456     # convert
 7457     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7458     # registers except esp clobbered at this point
 7459     # restore ed
 7460     89/<- %edx 4/r32/esp
 7461     (flush _test-output-buffered-file)
 7462     (flush _test-error-buffered-file)
 7463 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 7469     # check output
 7470     (check-stream-equal _test-output-stream  ""  "F - test-index-with-too-many-outputs: output should be empty")
 7471     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: too many outputs (1 required)"  "F - test-index-with-too-many-outputs: error message")
 7472     # check that stop(1) was called
 7473     (check-ints-equal *(edx+4) 2 "F - test-index-with-too-many-outputs: exit status")
 7474     # don't restore from ebp
 7475     81 0/subop/add %esp 8/imm32
 7476     # . epilogue
 7477     5d/pop-to-ebp
 7478     c3/return
 7479 
 7480 #######################################################
 7481 # Parsing
 7482 #######################################################
 7483 
 7484 == data
 7485 
 7486 # Global state added to each var record when parsing a function
 7487 Next-block-index:  # (addr int)
 7488     1/imm32
 7489 
 7490 Curr-block-depth:  # (addr int)
 7491     1/imm32
 7492 
 7493 == code
 7494 
 7495 parse-mu:  # in: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
 7496     # pseudocode
 7497     #   var curr-function: (addr handle function) = Program->functions
 7498     #   var curr-signature: (addr handle function) = Program->signatures
 7499     #   var curr-type: (addr handle typeinfo) = Program->types
 7500     #   var line: (stream byte 512)
 7501     #   var word-slice: slice
 7502     #   while true                                  # line loop
 7503     #     clear-stream(line)
 7504     #     read-line-buffered(in, line)
 7505     #     if (line->write == 0) break               # end of file
 7506     #     word-slice = next-mu-token(line)
 7507     #     if slice-empty?(word-slice)               # end of line
 7508     #       continue
 7509     #     else if slice-starts-with?(word-slice, "#")  # comment
 7510     #       continue                                # end of line
 7511     #     else if slice-equal?(word-slice, "fn")
 7512     #       var new-function: (handle function) = allocate(function)
 7513     #       var vars: (stack live-var 256)
 7514     #       populate-mu-function-header(line, new-function, vars)
 7515     #       populate-mu-function-body(in, new-function, vars)
 7516     #       assert(vars->top == 0)
 7517     #       *curr-function = new-function
 7518     #       curr-function = &new-function->next
 7519     #     else if slice-equal?(word-slice, "sig")
 7520     #       var new-function: (handle function) = allocate(function)
 7521     #       populate-mu-function-signature(line, new-function)
 7522     #       *curr-signature = new-function
 7523     #       curr-signature = &new-function->next
 7524     #     else if slice-equal?(word-slice, "type")
 7525     #       word-slice = next-mu-token(line)
 7526     #       type-id = pos-or-insert-slice(Type-id, word-slice)
 7527     #       var new-type: (handle typeinfo) = find-or-create-typeinfo(type-id)
 7528     #       assert(next-word(line) == "{")
 7529     #       populate-mu-type(in, new-type)
 7530     #     else
 7531     #       abort()
 7532     #
 7533     # . prologue
 7534     55/push-ebp
 7535     89/<- %ebp 4/r32/esp
 7536     # var curr-signature: (addr handle function) at *(ebp-4)
 7537     68/push _Program-signatures/imm32
 7538     # . save registers
 7539     50/push-eax
 7540     51/push-ecx
 7541     52/push-edx
 7542     53/push-ebx
 7543     56/push-esi
 7544     57/push-edi
 7545     # var line/ecx: (stream byte 512)
 7546     81 5/subop/subtract %esp 0x200/imm32
 7547     68/push 0x200/imm32/size
 7548     68/push 0/imm32/read
 7549     68/push 0/imm32/write
 7550     89/<- %ecx 4/r32/esp
 7551     # var word-slice/edx: slice
 7552     68/push 0/imm32/end
 7553     68/push 0/imm32/start
 7554     89/<- %edx 4/r32/esp
 7555     # var curr-function/edi: (addr handle function)
 7556     bf/copy-to-edi _Program-functions/imm32
 7557     # var vars/ebx: (stack live-var 256)
 7558     81 5/subop/subtract %esp 0xc00/imm32
 7559     68/push 0xc00/imm32/size
 7560     68/push 0/imm32/top
 7561     89/<- %ebx 4/r32/esp
 7562     {
 7563 $parse-mu:line-loop:
 7564       (clear-stream %ecx)
 7565       (read-line-buffered *(ebp+8) %ecx)
 7566       # if (line->write == 0) break
 7567       81 7/subop/compare *ecx 0/imm32
 7568       0f 84/jump-if-= break/disp32
 7569 +--  6 lines: #?       # dump line ------------------------------------------------------------------------------------------------------------------------------------------------------
 7575       (next-mu-token %ecx %edx)
 7576       # if slice-empty?(word-slice) continue
 7577       (slice-empty? %edx)  # => eax
 7578       3d/compare-eax-and 0/imm32/false
 7579       0f 85/jump-if-!= loop/disp32
 7580       # if (*word-slice->start == "#") continue
 7581       # . eax = *word-slice->start
 7582       8b/-> *edx 0/r32/eax
 7583       8a/copy-byte *eax 0/r32/AL
 7584       81 4/subop/and %eax 0xff/imm32
 7585       # . if (eax == '#') continue
 7586       3d/compare-eax-and 0x23/imm32/hash
 7587       0f 84/jump-if-= loop/disp32
 7588       # if (slice-equal?(word-slice, "fn")) parse a function
 7589       {
 7590 $parse-mu:fn:
 7591         (slice-equal? %edx "fn")  # => eax
 7592         3d/compare-eax-and 0/imm32/false
 7593         0f 84/jump-if-= break/disp32
 7594         # var new-function/esi: (handle function)
 7595         68/push 0/imm32
 7596         68/push 0/imm32
 7597         89/<- %esi 4/r32/esp
 7598         # populate-mu-function(line, in, vars, new-function)
 7599         (allocate Heap *Function-size %esi)
 7600         # var new-function-addr/eax: (addr function)
 7601         (lookup *esi *(esi+4))  # => eax
 7602         # initialize vars
 7603         (clear-stack %ebx)
 7604         #
 7605         (populate-mu-function-header %ecx %eax %ebx *(ebp+0xc) *(ebp+0x10))
 7606         (populate-mu-function-body *(ebp+8) %eax %ebx *(ebp+0xc) *(ebp+0x10))
 7607         # *curr-function = new-function
 7608         8b/-> *esi 0/r32/eax
 7609         89/<- *edi 0/r32/eax
 7610         8b/-> *(esi+4) 0/r32/eax
 7611         89/<- *(edi+4) 0/r32/eax
 7612         # curr-function = &new-function->next
 7613         # . var tmp/eax: (addr function) = lookup(new-function)
 7614         (lookup *esi *(esi+4))  # => eax
 7615         # . curr-function = &tmp->next
 7616         8d/copy-address *(eax+0x20) 7/r32/edi  # Function-next
 7617         # reclaim new-function
 7618         81 0/subop/add %esp 8/imm32
 7619         #
 7620         e9/jump $parse-mu:line-loop/disp32
 7621       }
 7622       # if (slice-equal?(word-slice, "sig")) parse a function signature
 7623       # Function signatures are for providing types to SubX functions.
 7624       {
 7625 $parse-mu:sig:
 7626         (slice-equal? %edx "sig")  # => eax
 7627         3d/compare-eax-and 0/imm32/false
 7628         0f 84/jump-if-= break/disp32
 7629         # edi = curr-function
 7630         57/push-edi
 7631         8b/-> *(ebp-4) 7/r32/edi
 7632         # var new-function/esi: (handle function)
 7633         68/push 0/imm32
 7634         68/push 0/imm32
 7635         89/<- %esi 4/r32/esp
 7636         # populate-mu-function(line, in, vars, new-function)
 7637         (allocate Heap *Function-size %esi)
 7638         # var new-function-addr/eax: (addr function)
 7639         (lookup *esi *(esi+4))  # => eax
 7640         #
 7641         (populate-mu-function-signature %ecx %eax *(ebp+0xc) *(ebp+0x10))
 7642         # *curr-signature = new-function
 7643         8b/-> *esi 0/r32/eax
 7644         89/<- *edi 0/r32/eax
 7645         8b/-> *(esi+4) 0/r32/eax
 7646         89/<- *(edi+4) 0/r32/eax
 7647         # curr-signature = &new-function->next
 7648         # . var tmp/eax: (addr function) = lookup(new-function)
 7649         (lookup *esi *(esi+4))  # => eax
 7650         # . curr-function = &tmp->next
 7651         8d/copy-address *(eax+0x20) 7/r32/edi  # Function-next
 7652         # reclaim new-function
 7653         81 0/subop/add %esp 8/imm32
 7654         # save curr-function
 7655         89/<- *(ebp-4) 7/r32/edi
 7656         # restore edi
 7657         5f/pop-to-edi
 7658         #
 7659         e9/jump $parse-mu:line-loop/disp32
 7660       }
 7661       # if (slice-equal?(word-slice, "type")) parse a type (struct/record) definition
 7662       {
 7663 $parse-mu:type:
 7664         (slice-equal? %edx "type")  # => eax
 7665         3d/compare-eax-and 0/imm32
 7666         0f 84/jump-if-= break/disp32
 7667         (next-mu-token %ecx %edx)
 7668         # var type-id/eax: int
 7669         (pos-or-insert-slice Type-id %edx)  # => eax
 7670         # spill
 7671         51/push-ecx
 7672         # var new-type/ecx: (handle typeinfo)
 7673         68/push 0/imm32
 7674         68/push 0/imm32
 7675         89/<- %ecx 4/r32/esp
 7676         (find-or-create-typeinfo %eax %ecx)
 7677         #
 7678         (lookup *ecx *(ecx+4))  # => eax
 7679         # TODO: ensure that 'line' has nothing else but '{'
 7680 #? (dump-typeinfos "=== aaa\n")
 7681         (populate-mu-type *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))  # => eax
 7682 #? (dump-typeinfos "=== zzz\n")
 7683         # reclaim new-type
 7684         81 0/subop/add %esp 8/imm32
 7685         # restore
 7686         59/pop-to-ecx
 7687         e9/jump $parse-mu:line-loop/disp32
 7688       }
 7689       # otherwise abort
 7690       e9/jump $parse-mu:error1/disp32
 7691     } # end line loop
 7692 $parse-mu:end:
 7693     # . reclaim locals
 7694     81 0/subop/add %esp 0x20c/imm32  # line
 7695     81 0/subop/add %esp 0xc08/imm32  # vars
 7696     81 0/subop/add %esp 8/imm32
 7697     # . restore registers
 7698     5f/pop-to-edi
 7699     5e/pop-to-esi
 7700     5b/pop-to-ebx
 7701     5a/pop-to-edx
 7702     59/pop-to-ecx
 7703     58/pop-to-eax
 7704     # . reclaim local
 7705     81 0/subop/add %esp 4/imm32
 7706     # . epilogue
 7707     89/<- %esp 5/r32/ebp
 7708     5d/pop-to-ebp
 7709     c3/return
 7710 
 7711 $parse-mu:error1:
 7712     # error("unexpected top-level command: " word-slice "\n")
 7713     (write-buffered *(ebp+0xc) "unexpected top-level command: ")
 7714     (write-slice-buffered *(ebp+0xc) %edx)
 7715     (write-buffered *(ebp+0xc) "\n")
 7716     (flush *(ebp+0xc))
 7717     (stop *(ebp+0x10) 1)
 7718     # never gets here
 7719 
 7720 $parse-mu:error2:
 7721     # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n")
 7722     (write-int32-hex-buffered *(ebp+0xc) *ebx)
 7723     (write-buffered *(ebp+0xc) " vars not reclaimed after fn '")
 7724     (write-slice-buffered *(ebp+0xc) *eax)  # Function-name
 7725     (write-buffered *(ebp+0xc) "'\n")
 7726     (flush *(ebp+0xc))
 7727     (stop *(ebp+0x10) 1)
 7728     # never gets here
 7729 
 7730 # scenarios considered:
 7731 # ✗ fn foo  # no block
 7732 # ✓ fn foo {
 7733 # ✗ fn foo { {
 7734 # ✗ fn foo { }
 7735 # ✗ fn foo { } {
 7736 # ✗ fn foo x {
 7737 # ✗ fn foo x: {
 7738 # ✓ fn foo x: int {
 7739 # ✓ fn foo x: int {
 7740 # ✓ fn foo x: int -> y/eax: int {
 7741 # TODO:
 7742 #   disallow outputs of type `(... addr ...)`
 7743 #   disallow inputs of type `(... addr ... addr ...)`
 7744 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)
 7745     # pseudocode:
 7746     #   var word-slice: slice
 7747     #   next-mu-token(first-line, word-slice)
 7748     #   assert(word-slice not in '{' '}' '->')
 7749     #   out->name = slice-to-string(word-slice)
 7750     #   ## inouts
 7751     #   while true
 7752     #     word-slice = next-mu-token(first-line)
 7753     #     if (word-slice == '{') goto done
 7754     #     if (word-slice == '->') break
 7755     #     assert(word-slice != '}')
 7756     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 7757     #     assert(v->register == null)
 7758     #     # v->block-depth is implicitly 0
 7759     #     out->inouts = append(v, out->inouts)
 7760     #     push(vars, {v, false})
 7761     #   ## outputs
 7762     #   while true
 7763     #     word-slice = next-mu-token(first-line)
 7764     #     if (word-slice == '{') break
 7765     #     assert(word-slice not in '}' '->')
 7766     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 7767     #     assert(v->register != null)
 7768     #     out->outputs = append(v, out->outputs)
 7769     #   done:
 7770     #
 7771     # . prologue
 7772     55/push-ebp
 7773     89/<- %ebp 4/r32/esp
 7774     # . save registers
 7775     50/push-eax
 7776     51/push-ecx
 7777     52/push-edx
 7778     53/push-ebx
 7779     57/push-edi
 7780     # edi = out
 7781     8b/-> *(ebp+0xc) 7/r32/edi
 7782     # var word-slice/ecx: slice
 7783     68/push 0/imm32/end
 7784     68/push 0/imm32/start
 7785     89/<- %ecx 4/r32/esp
 7786     # var v/ebx: (handle var)
 7787     68/push 0/imm32
 7788     68/push 0/imm32
 7789     89/<- %ebx 4/r32/esp
 7790     # read function name
 7791     (next-mu-token *(ebp+8) %ecx)
 7792     # error checking
 7793     # if (word-slice == '{') abort
 7794     (slice-equal? %ecx "{")   # => eax
 7795     3d/compare-eax-and 0/imm32/false
 7796     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 7797     # if (word-slice == '->') abort
 7798     (slice-equal? %ecx "->")   # => eax
 7799     3d/compare-eax-and 0/imm32/false
 7800     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 7801     # if (word-slice == '}') abort
 7802     (slice-equal? %ecx "}")   # => eax
 7803     3d/compare-eax-and 0/imm32/false
 7804     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 7805     # save function name
 7806     (slice-to-string Heap %ecx %edi)  # Function-name
 7807     # save function inouts
 7808     {
 7809 $populate-mu-function-header:check-for-inout:
 7810       (next-mu-token *(ebp+8) %ecx)
 7811       # if (word-slice == '{') goto done
 7812       (slice-equal? %ecx "{")   # => eax
 7813       3d/compare-eax-and 0/imm32/false
 7814       0f 85/jump-if-!= $populate-mu-function-header:done/disp32
 7815       # if (word-slice == '->') break
 7816       (slice-equal? %ecx "->")   # => eax
 7817       3d/compare-eax-and 0/imm32/false
 7818       0f 85/jump-if-!= break/disp32
 7819       # if (word-slice == '}') abort
 7820       (slice-equal? %ecx "}")   # => eax
 7821       3d/compare-eax-and 0/imm32/false
 7822       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 7823       # v = parse-var-with-type(word-slice, first-line)
 7824       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x14) *(ebp+0x18))
 7825       # assert(v->register == null)
 7826       # . eax: (addr var) = lookup(v)
 7827       (lookup *ebx *(ebx+4))  # => eax
 7828       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 7829       0f 85/jump-if-!= $populate-mu-function-header:error2/disp32
 7830       # v->block-depth is implicitly 0
 7831       #
 7832       # out->inouts = append(v, out->inouts)
 7833       8d/copy-address *(edi+8) 0/r32/eax  # Function-inouts
 7834       (append-list Heap  *ebx *(ebx+4)  *(edi+8) *(edi+0xc)  %eax)  # Function-inouts, Function-inouts
 7835       # push(vars, {v, false})
 7836       (push *(ebp+0x10) *ebx)
 7837       (push *(ebp+0x10) *(ebx+4))
 7838       (push *(ebp+0x10) 0)  # false
 7839       #
 7840       e9/jump loop/disp32
 7841     }
 7842     # save function outputs
 7843     {
 7844 $populate-mu-function-header:check-for-out:
 7845       (next-mu-token *(ebp+8) %ecx)
 7846       # if (word-slice == '{') break
 7847       (slice-equal? %ecx "{")   # => eax
 7848       3d/compare-eax-and 0/imm32/false
 7849       0f 85/jump-if-!= break/disp32
 7850       # if (word-slice == '->') abort
 7851       (slice-equal? %ecx "->")   # => eax
 7852       3d/compare-eax-and 0/imm32/false
 7853       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 7854       # if (word-slice == '}') abort
 7855       (slice-equal? %ecx "}")   # => eax
 7856       3d/compare-eax-and 0/imm32/false
 7857       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 7858       # v = parse-var-with-type(word-slice, first-line)
 7859       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x14) *(ebp+0x18))
 7860       # assert(var->register != null)
 7861       # . eax: (addr var) = lookup(v)
 7862       (lookup *ebx *(ebx+4))  # => eax
 7863       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 7864       0f 84/jump-if-= $populate-mu-function-header:error3/disp32
 7865       # out->outputs = append(v, out->outputs)
 7866       8d/copy-address *(edi+0x10) 0/r32/eax  # Function-outputs
 7867       (append-list Heap  *ebx *(ebx+4)  *(edi+0x10) *(edi+0x14)  %eax)  # Function-outputs, Function-outputs
 7868       #
 7869       e9/jump loop/disp32
 7870     }
 7871 $populate-mu-function-header:done:
 7872     (check-no-tokens-left *(ebp+8))
 7873 $populate-mu-function-header:end:
 7874     # . reclaim locals
 7875     81 0/subop/add %esp 0x10/imm32
 7876     # . restore registers
 7877     5f/pop-to-edi
 7878     5b/pop-to-ebx
 7879     5a/pop-to-edx
 7880     59/pop-to-ecx
 7881     58/pop-to-eax
 7882     # . epilogue
 7883     89/<- %esp 5/r32/ebp
 7884     5d/pop-to-ebp
 7885     c3/return
 7886 
 7887 $populate-mu-function-header:error1:
 7888     # error("function header not in form 'fn <name> {'")
 7889     (write-buffered *(ebp+0x14) "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '")
 7890     (flush *(ebp+0x14))
 7891     (rewind-stream *(ebp+8))
 7892     (write-stream-data *(ebp+0x14) *(ebp+8))
 7893     (write-buffered *(ebp+0x14) "'\n")
 7894     (flush *(ebp+0x14))
 7895     (stop *(ebp+0x18) 1)
 7896     # never gets here
 7897 
 7898 $populate-mu-function-header:error2:
 7899     # error("fn " fn ": function inout '" var "' cannot be in a register")
 7900     (write-buffered *(ebp+0x14) "fn ")
 7901     50/push-eax
 7902     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 7903     (write-buffered *(ebp+0x14) %eax)
 7904     58/pop-to-eax
 7905     (write-buffered *(ebp+0x14) ": function inout '")
 7906     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 7907     (write-buffered *(ebp+0x10) %eax)
 7908     (write-buffered *(ebp+0x14) "' cannot be in a register")
 7909     (flush *(ebp+0x14))
 7910     (stop *(ebp+0x18) 1)
 7911     # never gets here
 7912 
 7913 $populate-mu-function-header:error3:
 7914     # error("fn " fn ": function output '" var "' must be in a register")
 7915     (write-buffered *(ebp+0x14) "fn ")
 7916     50/push-eax
 7917     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 7918     (write-buffered *(ebp+0x14) %eax)
 7919     58/pop-to-eax
 7920     (write-buffered *(ebp+0x14) ": function output '")
 7921     (lookup *ebx *(ebx+4))  # => eax
 7922     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 7923     (write-buffered *(ebp+0x14) %eax)
 7924     (write-buffered *(ebp+0x14) "' must be in a register, in instruction '")
 7925     (rewind-stream *(ebp+8))
 7926     (write-stream-data *(ebp+0x14) *(ebp+8))
 7927     (write-buffered *(ebp+0x14) "'\n")
 7928     (flush *(ebp+0x14))
 7929     (stop *(ebp+0x18) 1)
 7930     # never gets here
 7931 
 7932 # scenarios considered:
 7933 # ✓ fn foo
 7934 # ✗ fn foo {
 7935 # ✓ fn foo x
 7936 # ✓ fn foo x: int
 7937 # ✓ fn foo x: int -> y/eax: int
 7938 # TODO:
 7939 #   disallow outputs of type `(... addr ...)`
 7940 #   disallow inputs of type `(... addr ... addr ...)`
 7941 populate-mu-function-signature:  # first-line: (addr stream byte), out: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
 7942     # pseudocode:
 7943     #   var word-slice: slice
 7944     #   next-mu-token(first-line, word-slice)
 7945     #   assert(word-slice not in '{' '}' '->')
 7946     #   out->name = slice-to-string(word-slice)
 7947     #   ## inouts
 7948     #   while true
 7949     #     word-slice = next-mu-token(first-line)
 7950     #     if slice-empty?(word-slice) break
 7951     #     if (word-slice == '->') break
 7952     #     assert(word-slice not in '{' '}')
 7953     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 7954     #     assert(v->register == null)
 7955     #     # v->block-depth is implicitly 0
 7956     #     out->inouts = append(v, out->inouts)
 7957     #   ## outputs
 7958     #   while true
 7959     #     word-slice = next-mu-token(first-line)
 7960     #     if slice-empty?(word-slice) break
 7961     #     assert(word-slice not in '{' '}' '->')
 7962     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 7963     #     assert(v->register != null)
 7964     #     out->outputs = append(v, out->outputs)
 7965     #
 7966     # . prologue
 7967     55/push-ebp
 7968     89/<- %ebp 4/r32/esp
 7969     # . save registers
 7970     50/push-eax
 7971     51/push-ecx
 7972     52/push-edx
 7973     53/push-ebx
 7974     57/push-edi
 7975     # edi = out
 7976     8b/-> *(ebp+0xc) 7/r32/edi
 7977     # var word-slice/ecx: slice
 7978     68/push 0/imm32/end
 7979     68/push 0/imm32/start
 7980     89/<- %ecx 4/r32/esp
 7981     # var v/ebx: (handle var)
 7982     68/push 0/imm32
 7983     68/push 0/imm32
 7984     89/<- %ebx 4/r32/esp
 7985     # read function name
 7986     (next-mu-token *(ebp+8) %ecx)
 7987     # error checking
 7988     # if (word-slice == '{') abort
 7989     (slice-equal? %ecx "{")   # => eax
 7990     3d/compare-eax-and 0/imm32/false
 7991     0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7992     # if (word-slice == '->') abort
 7993     (slice-equal? %ecx "->")   # => eax
 7994     3d/compare-eax-and 0/imm32/false
 7995     0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 7996     # if (word-slice == '}') abort
 7997     (slice-equal? %ecx "}")   # => eax
 7998     3d/compare-eax-and 0/imm32/false
 7999     0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 8000     # save function name
 8001     (slice-to-string Heap %ecx %edi)  # Function-name
 8002     # save function inouts
 8003     {
 8004 $populate-mu-function-signature:check-for-inout:
 8005       (next-mu-token *(ebp+8) %ecx)
 8006       (slice-empty? %ecx)  # => eax
 8007       3d/compare-eax-and 0/imm32/false
 8008       0f 85/jump-if-!= break/disp32
 8009       # if (word-slice == '->') break
 8010       (slice-equal? %ecx "->")   # => eax
 8011       3d/compare-eax-and 0/imm32/false
 8012       0f 85/jump-if-!= break/disp32
 8013       # if (word-slice == '{') abort
 8014       (slice-equal? %ecx "{")   # => eax
 8015       3d/compare-eax-and 0/imm32/false
 8016       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 8017       # if (word-slice == '}') abort
 8018       (slice-equal? %ecx "}")   # => eax
 8019       3d/compare-eax-and 0/imm32/false
 8020       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 8021       # v = parse-var-with-type(word-slice, first-line)
 8022       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x10) *(ebp+0x14))
 8023       # assert(v->register == null)
 8024       # . eax: (addr var) = lookup(v)
 8025       (lookup *ebx *(ebx+4))  # => eax
 8026       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 8027       0f 85/jump-if-!= $populate-mu-function-signature:error2/disp32
 8028       # v->block-depth is implicitly 0
 8029       #
 8030       # out->inouts = append(v, out->inouts)
 8031       8d/copy-address *(edi+8) 0/r32/eax  # Function-inouts
 8032       (append-list Heap  *ebx *(ebx+4)  *(edi+8) *(edi+0xc)  %eax)  # Function-inouts, Function-inouts
 8033       #
 8034       e9/jump loop/disp32
 8035     }
 8036     # save function outputs
 8037     {
 8038 $populate-mu-function-signature:check-for-out:
 8039       (next-mu-token *(ebp+8) %ecx)
 8040       (slice-empty? %ecx)  # => eax
 8041       3d/compare-eax-and 0/imm32/false
 8042       0f 85/jump-if-!= break/disp32
 8043       # if (word-slice == '{') abort
 8044       (slice-equal? %ecx "{")   # => eax
 8045       3d/compare-eax-and 0/imm32/false
 8046       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 8047       # if (word-slice == '->') abort
 8048       (slice-equal? %ecx "->")   # => eax
 8049       3d/compare-eax-and 0/imm32/false
 8050       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 8051       # if (word-slice == '}') abort
 8052       (slice-equal? %ecx "}")   # => eax
 8053       3d/compare-eax-and 0/imm32/false
 8054       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 8055       # v = parse-var-with-type(word-slice, first-line)
 8056       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x10) *(ebp+0x14))
 8057       # assert(var->register != null)
 8058       # . eax: (addr var) = lookup(v)
 8059       (lookup *ebx *(ebx+4))  # => eax
 8060       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 8061       0f 84/jump-if-= $populate-mu-function-signature:error3/disp32
 8062       # out->outputs = append(v, out->outputs)
 8063       8d/copy-address *(edi+0x10) 0/r32/eax  # Function-outputs
 8064       (append-list Heap  *ebx *(ebx+4)  *(edi+0x10) *(edi+0x14)  %eax)  # Function-outputs, Function-outputs
 8065       #
 8066       e9/jump loop/disp32
 8067     }
 8068 $populate-mu-function-signature:done:
 8069     (check-no-tokens-left *(ebp+8))
 8070 $populate-mu-function-signature:end:
 8071     # . reclaim locals
 8072     81 0/subop/add %esp 0x10/imm32
 8073     # . restore registers
 8074     5f/pop-to-edi
 8075     5b/pop-to-ebx
 8076     5a/pop-to-edx
 8077     59/pop-to-ecx
 8078     58/pop-to-eax
 8079     # . epilogue
 8080     89/<- %esp 5/r32/ebp
 8081     5d/pop-to-ebp
 8082     c3/return
 8083 
 8084 $populate-mu-function-signature:error1:
 8085     # error("function signature not in form 'fn <name> {'")
 8086     (write-buffered *(ebp+0x10) "function signature not in form 'fn <name> [inouts] [-> outputs] {' -- '")
 8087     (flush *(ebp+0x10))
 8088     (rewind-stream *(ebp+8))
 8089     (write-stream-data *(ebp+0x10) *(ebp+8))
 8090     (write-buffered *(ebp+0x10) "'\n")
 8091     (flush *(ebp+0x10))
 8092     (stop *(ebp+0x14) 1)
 8093     # never gets here
 8094 
 8095 $populate-mu-function-signature:error2:
 8096     # error("fn " fn ": function inout '" var "' cannot be in a register")
 8097     (write-buffered *(ebp+0x10) "fn ")
 8098     50/push-eax
 8099     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 8100     (write-buffered *(ebp+0x10) %eax)
 8101     58/pop-to-eax
 8102     (write-buffered *(ebp+0x10) ": function inout '")
 8103     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 8104     (write-buffered *(ebp+0x10) %eax)
 8105     (write-buffered *(ebp+0x10) "' cannot be in a register")
 8106     (flush *(ebp+0x10))
 8107     (stop *(ebp+0x14) 1)
 8108     # never gets here
 8109 
 8110 $populate-mu-function-signature:error3:
 8111     # error("fn " fn ": function output '" var "' must be in a register")
 8112     (write-buffered *(ebp+0x10) "fn ")
 8113     50/push-eax
 8114     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 8115     (write-buffered *(ebp+0x10) %eax)
 8116     58/pop-to-eax
 8117     (write-buffered *(ebp+0x10) ": function output '")
 8118     (lookup *ebx *(ebx+4))  # => eax
 8119     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 8120     (write-buffered *(ebp+0x10) %eax)
 8121     (write-buffered *(ebp+0x10) "' must be in a register, in instruction '")
 8122     (rewind-stream *(ebp+8))
 8123     (write-stream-data *(ebp+0x10) *(ebp+8))
 8124     (write-buffered *(ebp+0x10) "'\n")
 8125     (flush *(ebp+0x10))
 8126     (stop *(ebp+0x14) 1)
 8127     # never gets here
 8128 
 8129 test-function-header-with-arg:
 8130     # . prologue
 8131     55/push-ebp
 8132     89/<- %ebp 4/r32/esp
 8133     # setup
 8134     (clear-stream _test-input-stream)
 8135     (write _test-input-stream "foo n: int {\n")
 8136     # var result/ecx: function
 8137     2b/subtract *Function-size 4/r32/esp
 8138     89/<- %ecx 4/r32/esp
 8139     (zero-out %ecx *Function-size)
 8140     # var vars/ebx: (stack live-var 16)
 8141     81 5/subop/subtract %esp 0xc0/imm32
 8142     68/push 0xc0/imm32/size
 8143     68/push 0/imm32/top
 8144     89/<- %ebx 4/r32/esp
 8145     # convert
 8146     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 8147     # check result->name
 8148     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 8149     (check-strings-equal %eax "foo" "F - test-function-header-with-arg/name")
 8150     # var v/edx: (addr var) = result->inouts->value
 8151     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 8152     (lookup *eax *(eax+4))  # List-value List-value => eax
 8153     89/<- %edx 0/r32/eax
 8154     # check v->name
 8155     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 8156     (check-strings-equal %eax "n" "F - test-function-header-with-arg/inout:0")
 8157     # check v->type
 8158     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 8159     (check-ints-equal *eax 1 "F - test-function-header-with-arg/inout:0/type:0")  # Type-tree-is-atom
 8160     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-arg/inout:0/type:1")  # Type-tree-value
 8161     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-arg/inout:0/type:2")  # Type-tree-right
 8162     # . epilogue
 8163     89/<- %esp 5/r32/ebp
 8164     5d/pop-to-ebp
 8165     c3/return
 8166 
 8167 test-function-header-with-multiple-args:
 8168     # . prologue
 8169     55/push-ebp
 8170     89/<- %ebp 4/r32/esp
 8171     # setup
 8172     (clear-stream _test-input-stream)
 8173     (write _test-input-stream "foo a: int, b: int c: int {\n")
 8174     # result/ecx: function
 8175     2b/subtract *Function-size 4/r32/esp
 8176     89/<- %ecx 4/r32/esp
 8177     (zero-out %ecx *Function-size)
 8178     # var vars/ebx: (stack live-var 16)
 8179     81 5/subop/subtract %esp 0xc0/imm32
 8180     68/push 0xc0/imm32/size
 8181     68/push 0/imm32/top
 8182     89/<- %ebx 4/r32/esp
 8183     # convert
 8184     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 8185     # check result->name
 8186     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 8187     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args/name")
 8188     # var inouts/edx: (addr list var) = lookup(result->inouts)
 8189     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 8190     89/<- %edx 0/r32/eax
 8191 $test-function-header-with-multiple-args:inout0:
 8192     # var v/ebx: (addr var) = lookup(inouts->value)
 8193     (lookup *edx *(edx+4))  # List-value List-value => eax
 8194     89/<- %ebx 0/r32/eax
 8195     # check v->name
 8196     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 8197     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args/inout:0")  # Var-name
 8198     # check v->type
 8199     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 8200     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:0/type:0")  # Type-tree-is-atom
 8201     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:0/type:1")  # Type-tree-value
 8202     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:0/type:2")  # Type-tree-right
 8203 $test-function-header-with-multiple-args:inout1:
 8204     # inouts = lookup(inouts->next)
 8205     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 8206     89/<- %edx 0/r32/eax
 8207     # v = lookup(inouts->value)
 8208     (lookup *edx *(edx+4))  # List-value List-value => eax
 8209     89/<- %ebx 0/r32/eax
 8210     # check v->name
 8211     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 8212     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args/inout:1")  # Var-name
 8213     # check v->type
 8214     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 8215     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:1/type:0")  # Type-tree-is-atom
 8216     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:1/type:1")  # Type-tree-value
 8217     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:1/type:2")  # Type-tree-right
 8218 $test-function-header-with-multiple-args:inout2:
 8219     # inouts = lookup(inouts->next)
 8220     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 8221     89/<- %edx 0/r32/eax
 8222     # v = lookup(inouts->value)
 8223     (lookup *edx *(edx+4))  # List-value List-value => eax
 8224     89/<- %ebx 0/r32/eax
 8225     # check v->name
 8226     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 8227     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args/inout:2")  # Var-name
 8228     # check v->type
 8229     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 8230     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:2/type:0")  # Type-tree-is-atom
 8231     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:2/type:1")  # Type-tree-value
 8232     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:2/type:2")  # Type-tree-right
 8233     # . epilogue
 8234     89/<- %esp 5/r32/ebp
 8235     5d/pop-to-ebp
 8236     c3/return
 8237 
 8238 test-function-header-with-multiple-args-and-outputs:
 8239     # . prologue
 8240     55/push-ebp
 8241     89/<- %ebp 4/r32/esp
 8242     # setup
 8243     (clear-stream _test-input-stream)
 8244     (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx: int {\n")
 8245     # result/ecx: function
 8246     2b/subtract *Function-size 4/r32/esp
 8247     89/<- %ecx 4/r32/esp
 8248     (zero-out %ecx *Function-size)
 8249     # var vars/ebx: (stack live-var 16)
 8250     81 5/subop/subtract %esp 0xc0/imm32
 8251     68/push 0xc0/imm32/size
 8252     68/push 0/imm32/top
 8253     89/<- %ebx 4/r32/esp
 8254     # convert
 8255     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 8256     # check result->name
 8257     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 8258     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args-and-outputs/name")
 8259     # var inouts/edx: (addr list var) = lookup(result->inouts)
 8260     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 8261     89/<- %edx 0/r32/eax
 8262 $test-function-header-with-multiple-args-and-outputs:inout0:
 8263     # var v/ebx: (addr var) = lookup(inouts->value)
 8264     (lookup *edx *(edx+4))  # List-value List-value => eax
 8265     89/<- %ebx 0/r32/eax
 8266     # check v->name
 8267     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 8268     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args-and-outputs/inout:0")
 8269     # check v->type
 8270     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 8271     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:0")  # Type-tree-is-atom
 8272     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1")  # Type-tree-value
 8273     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:2")  # Type-tree-right
 8274 $test-function-header-with-multiple-args-and-outputs:inout1:
 8275     # inouts = lookup(inouts->next)
 8276     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 8277     89/<- %edx 0/r32/eax
 8278     # v = lookup(inouts->value)
 8279     (lookup *edx *(edx+4))  # List-value List-value => eax
 8280     89/<- %ebx 0/r32/eax
 8281     # check v->name
 8282     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 8283     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args-and-outputs/inout:1")
 8284     # check v->type
 8285     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 8286     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:0")  # Type-tree-is-atom
 8287     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1")  # Type-tree-value
 8288     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:2")  # Type-tree-right
 8289 $test-function-header-with-multiple-args-and-outputs:inout2:
 8290     # inouts = lookup(inouts->next)
 8291     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 8292     89/<- %edx 0/r32/eax
 8293     # v = lookup(inouts->value)
 8294     (lookup *edx *(edx+4))  # List-value List-value => eax
 8295     89/<- %ebx 0/r32/eax
 8296     # check v->name
 8297     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 8298     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args-and-outputs/inout:2")
 8299     # check v->type
 8300     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 8301     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:0")  # Type-tree-is-atom
 8302     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1")  # Type-tree-value
 8303     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:2")  # Type-tree-right
 8304 $test-function-header-with-multiple-args-and-outputs:out0:
 8305     # var outputs/edx: (addr list var) = lookup(result->outputs)
 8306     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
 8307     89/<- %edx 0/r32/eax
 8308     # v = lookup(outputs->value)
 8309     (lookup *edx *(edx+4))  # List-value List-value => eax
 8310     89/<- %ebx 0/r32/eax
 8311     # check v->name
 8312     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 8313     (check-strings-equal %eax "x" "F - test-function-header-with-multiple-args-and-outputs/output:0")
 8314     # check v->register
 8315     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 8316     (check-strings-equal %eax "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register")
 8317     # check v->type
 8318     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 8319     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:0")  # Type-tree-is-atom
 8320     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1")  # Type-tree-value
 8321     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:2")  # Type-tree-right
 8322 $test-function-header-with-multiple-args-and-outputs:out1:
 8323     # outputs = lookup(outputs->next)
 8324     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 8325     89/<- %edx 0/r32/eax
 8326     # v = lookup(inouts->value)
 8327     (lookup *edx *(edx+4))  # List-value List-value => eax
 8328     89/<- %ebx 0/r32/eax
 8329     # check v->name
 8330     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 8331     (check-strings-equal %eax "y" "F - test-function-header-with-multiple-args-and-outputs/output:1")
 8332     # check v->register
 8333     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 8334     (check-strings-equal %eax "edx" "F - test-function-header-with-multiple-args-and-outputs/output:1/register")
 8335     # check v->type
 8336     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 8337     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:0")  # Type-tree-is-atom
 8338     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1")  # Type-tree-value
 8339     (check-ints-equal *(eax+0c) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:2")  # Type-tree-right
 8340     # . epilogue
 8341     89/<- %esp 5/r32/ebp
 8342     5d/pop-to-ebp
 8343     c3/return
 8344 
 8345 # format for variables with types
 8346 #   x: int
 8347 #   x: int,
 8348 #   x/eax: int
 8349 #   x/eax: int,
 8350 # ignores at most one trailing comma
 8351 # WARNING: modifies name
 8352 parse-var-with-type:  # name: (addr slice), first-line: (addr stream byte), out: (addr handle var), err: (addr buffered-file), ed: (addr exit-descriptor)
 8353     # pseudocode:
 8354     #   var s: slice
 8355     #   if (!slice-ends-with(name, ":"))
 8356     #     abort
 8357     #   --name->end to skip ':'
 8358     #   next-token-from-slice(name->start, name->end, '/', s)
 8359     #   new-var-from-slice(s, out)
 8360     #   ## register
 8361     #   next-token-from-slice(s->end, name->end, '/', s)
 8362     #   if (!slice-empty?(s))
 8363     #     out->register = slice-to-string(s)
 8364     #   ## type
 8365     #   var type: (handle type-tree) = parse-type(first-line)
 8366     #   out->type = type
 8367     #
 8368     # . prologue
 8369     55/push-ebp
 8370     89/<- %ebp 4/r32/esp
 8371     # . save registers
 8372     50/push-eax
 8373     51/push-ecx
 8374     52/push-edx
 8375     53/push-ebx
 8376     56/push-esi
 8377     57/push-edi
 8378     # esi = name
 8379     8b/-> *(ebp+8) 6/r32/esi
 8380     # if (!slice-ends-with?(name, ":")) abort
 8381     8b/-> *(esi+4) 1/r32/ecx  # Slice-end
 8382     49/decrement-ecx
 8383     8a/copy-byte *ecx 1/r32/CL
 8384     81 4/subop/and %ecx 0xff/imm32
 8385     81 7/subop/compare %ecx 0x3a/imm32/colon
 8386     0f 85/jump-if-!= $parse-var-with-type:abort/disp32
 8387     # --name->end to skip ':'
 8388     ff 1/subop/decrement *(esi+4)
 8389     # var s/ecx: slice
 8390     68/push 0/imm32/end
 8391     68/push 0/imm32/start
 8392     89/<- %ecx 4/r32/esp
 8393 $parse-var-with-type:parse-name:
 8394     (next-token-from-slice *esi *(esi+4) 0x2f %ecx)  # Slice-start, Slice-end, '/'
 8395 $parse-var-with-type:create-var:
 8396     # new-var-from-slice(s, out)
 8397     (new-var-from-slice Heap %ecx *(ebp+0x10))
 8398     # save out->register
 8399 $parse-var-with-type:save-register:
 8400     # . var out-addr/edi: (addr var) = lookup(*out)
 8401     8b/-> *(ebp+0x10) 7/r32/edi
 8402     (lookup *edi *(edi+4))  # => eax
 8403     89/<- %edi 0/r32/eax
 8404     # . s = next-token(...)
 8405     (next-token-from-slice *(ecx+4) *(esi+4) 0x2f %ecx)  # s->end, name->end, '/'
 8406     # . if (!slice-empty?(s)) out->register = slice-to-string(s)
 8407     {
 8408 $parse-var-with-type:write-register:
 8409       (slice-empty? %ecx)  # => eax
 8410       3d/compare-eax-and 0/imm32/false
 8411       75/jump-if-!= break/disp8
 8412       # out->register = slice-to-string(s)
 8413       8d/copy-address *(edi+0x18) 0/r32/eax  # Var-register
 8414       (slice-to-string Heap %ecx %eax)
 8415     }
 8416 $parse-var-with-type:save-type:
 8417     8d/copy-address *(edi+8) 0/r32/eax  # Var-type
 8418     (parse-type Heap *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 8419 $parse-var-with-type:end:
 8420     # . reclaim locals
 8421     81 0/subop/add %esp 8/imm32
 8422     # . restore registers
 8423     5f/pop-to-edi
 8424     5e/pop-to-esi
 8425     5b/pop-to-ebx
 8426     5a/pop-to-edx
 8427     59/pop-to-ecx
 8428     58/pop-to-eax
 8429     # . epilogue
 8430     89/<- %esp 5/r32/ebp
 8431     5d/pop-to-ebp
 8432     c3/return
 8433 
 8434 $parse-var-with-type:abort:
 8435     # error("var should have form 'name: type' in '" line "'\n")
 8436     (write-buffered *(ebp+0x14) "var should have form 'name: type' in '")
 8437     (flush *(ebp+0x14))
 8438     (rewind-stream *(ebp+0xc))
 8439     (write-stream-data *(ebp+0x14) *(ebp+0xc))
 8440     (write-buffered *(ebp+0x14) "'\n")
 8441     (flush *(ebp+0x14))
 8442     (stop *(ebp+0x18) 1)
 8443     # never gets here
 8444 
 8445 parse-type:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle type-tree), err: (addr buffered-file), ed: (addr exit-descriptor)
 8446     # pseudocode:
 8447     #   var s: slice = next-mu-token(in)
 8448     #   assert s != ""
 8449     #   assert s != "->"
 8450     #   assert s != "{"
 8451     #   assert s != "}"
 8452     #   if s == ")"
 8453     #     return
 8454     #   out = allocate(Type-tree)
 8455     #   if s != "("
 8456     #     HACK: if s is an int, parse and return it
 8457     #     out->is-atom? = true
 8458     #     if (s[0] == "_")
 8459     #       out->value = type-parameter
 8460     #       out->parameter-name = slice-to-string(ad, s)
 8461     #     else
 8462     #       out->value = pos-or-insert-slice(Type-id, s)
 8463     #     return
 8464     #   out->left = parse-type(ad, in)
 8465     #   out->right = parse-type-tree(ad, in)
 8466     #
 8467     # . prologue
 8468     55/push-ebp
 8469     89/<- %ebp 4/r32/esp
 8470     # . save registers
 8471     50/push-eax
 8472     51/push-ecx
 8473     52/push-edx
 8474     # clear out
 8475     (zero-out *(ebp+0x10) *Handle-size)
 8476     # var s/ecx: slice
 8477     68/push 0/imm32
 8478     68/push 0/imm32
 8479     89/<- %ecx 4/r32/esp
 8480     # s = next-mu-token(in)
 8481     (next-mu-token *(ebp+0xc) %ecx)
 8482 #?     (write-buffered Stderr "tok: ")
 8483 #?     (write-slice-buffered Stderr %ecx)
 8484 #?     (write-buffered Stderr "$\n")
 8485 #?     (flush Stderr)
 8486     # assert s != ""
 8487     (slice-equal? %ecx "")  # => eax
 8488     3d/compare-eax-and 0/imm32/false
 8489     0f 85/jump-if-!= $parse-type:abort/disp32
 8490     # assert s != "{"
 8491     (slice-equal? %ecx "{")  # => eax
 8492     3d/compare-eax-and 0/imm32/false
 8493     0f 85/jump-if-!= $parse-type:abort/disp32
 8494     # assert s != "}"
 8495     (slice-equal? %ecx "}")  # => eax
 8496     3d/compare-eax-and 0/imm32/false
 8497     0f 85/jump-if-!= $parse-type:abort/disp32
 8498     # assert s != "->"
 8499     (slice-equal? %ecx "->")  # => eax
 8500     3d/compare-eax-and 0/imm32/false
 8501     0f 85/jump-if-!= $parse-type:abort/disp32
 8502     # if (s == ")") return
 8503     (slice-equal? %ecx ")")  # => eax
 8504     3d/compare-eax-and 0/imm32/false
 8505     0f 85/jump-if-!= $parse-type:end/disp32
 8506     # out = new tree
 8507     (allocate *(ebp+8) *Type-tree-size *(ebp+0x10))
 8508     # var out-addr/edx: (addr type-tree) = lookup(*out)
 8509     8b/-> *(ebp+0x10) 2/r32/edx
 8510     (lookup *edx *(edx+4))  # => eax
 8511     89/<- %edx 0/r32/eax
 8512     {
 8513       # if (s != "(") break
 8514       (slice-equal? %ecx "(")  # => eax
 8515       3d/compare-eax-and 0/imm32/false
 8516       0f 85/jump-if-!= break/disp32
 8517       # if s is a number, store it in the type's size field
 8518       {
 8519 $parse-type:check-for-int:
 8520         # var tmp/eax: byte = *s->slice
 8521         8b/-> *ecx 0/r32/eax
 8522         8a/copy-byte *eax 0/r32/AL
 8523         81 4/subop/and %eax 0xff/imm32
 8524         # TODO: raise an error on `var x: (array int a)`
 8525         (is-decimal-digit? %eax)  # => eax
 8526         3d/compare-eax-and 0/imm32/false
 8527         74/jump-if-= break/disp8
 8528         #
 8529         (is-hex-int? %ecx)  # => eax
 8530         3d/compare-eax-and 0/imm32/false
 8531         74/jump-if-= break/disp8
 8532 $parse-type:int:
 8533         (check-mu-hex-int %ecx *(ebp+0x14) *(ebp+0x18))
 8534         (parse-hex-int-from-slice %ecx)  # => eax
 8535         c7 0/subop/copy *(edx+4) 9/imm32/type-id-array-capacity  # Type-tree-value
 8536         89/<- *(edx+8) 0/r32/eax  # Type-tree-value-size
 8537         e9/jump $parse-type:end/disp32
 8538       }
 8539 $parse-type:atom:
 8540       # out->is-atom? = true
 8541       c7 0/subop/copy *edx 1/imm32/true  # Type-tree-is-atom
 8542       {
 8543 $parse-type:check-for-type-parameter:
 8544         # var tmp/eax: byte = *s->slice
 8545         8b/-> *ecx 0/r32/eax
 8546         8a/copy-byte *eax 0/r32/AL
 8547         81 4/subop/and %eax 0xff/imm32
 8548         # if (tmp != '_') break
 8549         3d/compare-eax-and 0x5f/imm32/_
 8550         75/jump-if-!= break/disp8
 8551 $parse-type:type-parameter:
 8552         # out->value = type-parameter
 8553         c7 0/subop/copy *(edx+4) 0xa/imm32/type-parameter  # Type-tree-value
 8554         # out->parameter-name = slice-to-string(ad, s)
 8555         8d/copy-address *(edx+8) 0/r32/eax  # Type-tree-parameter-name
 8556         (slice-to-string *(ebp+8) %ecx %eax)
 8557         e9/jump $parse-type:end/disp32
 8558       }
 8559 $parse-type:non-type-parameter:
 8560       # out->value = pos-or-insert-slice(Type-id, s)
 8561       (pos-or-insert-slice Type-id %ecx)  # => eax
 8562       89/<- *(edx+4) 0/r32/eax  # Type-tree-value
 8563       e9/jump $parse-type:end/disp32
 8564     }
 8565 $parse-type:non-atom:
 8566     # otherwise s == "("
 8567     # out->left = parse-type(ad, in)
 8568     8d/copy-address *(edx+4) 0/r32/eax  # Type-tree-left
 8569     (parse-type *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 8570     # out->right = parse-type-tree(ad, in)
 8571     8d/copy-address *(edx+0xc) 0/r32/eax  # Type-tree-right
 8572     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 8573 $parse-type:end:
 8574     # . reclaim locals
 8575     81 0/subop/add %esp 8/imm32
 8576     # . restore registers
 8577     5a/pop-to-edx
 8578     59/pop-to-ecx
 8579     58/pop-to-eax
 8580     # . epilogue
 8581     89/<- %esp 5/r32/ebp
 8582     5d/pop-to-ebp
 8583     c3/return
 8584 
 8585 $parse-type:abort:
 8586     # error("unexpected token when parsing type: '" s "'\n")
 8587     (write-buffered *(ebp+0x14) "unexpected token when parsing type: '")
 8588     (write-slice-buffered *(ebp+0x14) %ecx)
 8589     (write-buffered *(ebp+0x14) "'\n")
 8590     (flush *(ebp+0x14))
 8591     (stop *(ebp+0x18) 1)
 8592     # never gets here
 8593 
 8594 parse-type-tree:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle type-tree), err: (addr buffered-file), ed: (addr exit-descriptor)
 8595     # pseudocode:
 8596     #   var tmp: (handle type-tree) = parse-type(ad, in)
 8597     #   if tmp == 0
 8598     #     return 0
 8599     #   out = allocate(Type-tree)
 8600     #   out->left = tmp
 8601     #   out->right = parse-type-tree(ad, in)
 8602     #
 8603     # . prologue
 8604     55/push-ebp
 8605     89/<- %ebp 4/r32/esp
 8606     # . save registers
 8607     50/push-eax
 8608     51/push-ecx
 8609     52/push-edx
 8610     #
 8611     (zero-out *(ebp+0x10) *Handle-size)
 8612     # var tmp/ecx: (handle type-tree)
 8613     68/push 0/imm32
 8614     68/push 0/imm32
 8615     89/<- %ecx 4/r32/esp
 8616     # tmp = parse-type(ad, in)
 8617     (parse-type *(ebp+8) *(ebp+0xc) %ecx *(ebp+0x14) *(ebp+0x18))
 8618     # if (tmp == 0) return
 8619     81 7/subop/compare *ecx 0/imm32
 8620     74/jump-if-= $parse-type-tree:end/disp8
 8621     # out = new tree
 8622     (allocate *(ebp+8) *Type-tree-size *(ebp+0x10))
 8623     # var out-addr/edx: (addr tree) = lookup(*out)
 8624     8b/-> *(ebp+0x10) 2/r32/edx
 8625     (lookup *edx *(edx+4))  # => eax
 8626     89/<- %edx 0/r32/eax
 8627     # out->left = tmp
 8628     8b/-> *ecx 0/r32/eax
 8629     89/<- *(edx+4) 0/r32/eax  # Type-tree-left
 8630     8b/-> *(ecx+4) 0/r32/eax
 8631     89/<- *(edx+8) 0/r32/eax  # Type-tree-left
 8632     # out->right = parse-type-tree(ad, in)
 8633     8d/copy-address *(edx+0xc) 0/r32/eax  # Type-tree-right
 8634     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 8635 $parse-type-tree:end:
 8636     # . reclaim locals
 8637     81 0/subop/add %esp 8/imm32
 8638     # . restore registers
 8639     5a/pop-to-edx
 8640     59/pop-to-ecx
 8641     58/pop-to-eax
 8642     # . epilogue
 8643     89/<- %esp 5/r32/ebp
 8644     5d/pop-to-ebp
 8645     c3/return
 8646 
 8647 next-mu-token:  # in: (addr stream byte), out: (addr slice)
 8648     # pseudocode:
 8649     # start:
 8650     #   skip-chars-matching-whitespace(in)
 8651     #   if in->read >= in->write              # end of in
 8652     #     out = {0, 0}
 8653     #     return
 8654     #   out->start = &in->data[in->read]
 8655     #   var curr-byte/eax: byte = in->data[in->read]
 8656     #   if curr->byte == ','                  # comment token
 8657     #     ++in->read
 8658     #     goto start
 8659     #   if curr-byte == '#'                   # comment
 8660     #     goto done                             # treat as eof
 8661     #   if curr-byte == '"'                   # string literal
 8662     #     skip-string(in)
 8663     #     goto done                           # no metadata
 8664     #   if curr-byte == '('
 8665     #     ++in->read
 8666     #     goto done
 8667     #   if curr-byte == ')'
 8668     #     ++in->read
 8669     #     goto done
 8670     #   # read a word
 8671     #   while true
 8672     #     if in->read >= in->write
 8673     #       break
 8674     #     curr-byte = in->data[in->read]
 8675     #     if curr-byte == ' '
 8676     #       break
 8677     #     if curr-byte == '\r'
 8678     #       break
 8679     #     if curr-byte == '\n'
 8680     #       break
 8681     #     if curr-byte == '('
 8682     #       break
 8683     #     if curr-byte == ')'
 8684     #       break
 8685     #     if curr-byte == ','
 8686     #       break
 8687     #     ++in->read
 8688     # done:
 8689     #   out->end = &in->data[in->read]
 8690     #
 8691     # . prologue
 8692     55/push-ebp
 8693     89/<- %ebp 4/r32/esp
 8694     # . save registers
 8695     50/push-eax
 8696     51/push-ecx
 8697     56/push-esi
 8698     57/push-edi
 8699     # esi = in
 8700     8b/-> *(ebp+8) 6/r32/esi
 8701     # edi = out
 8702     8b/-> *(ebp+0xc) 7/r32/edi
 8703 $next-mu-token:start:
 8704     (skip-chars-matching-whitespace %esi)
 8705 $next-mu-token:check0:
 8706     # if (in->read >= in->write) return out = {0, 0}
 8707     # . ecx = in->read
 8708     8b/-> *(esi+4) 1/r32/ecx
 8709     # . if (ecx >= in->write) return out = {0, 0}
 8710     3b/compare<- *esi 1/r32/ecx
 8711     c7 0/subop/copy *edi 0/imm32
 8712     c7 0/subop/copy *(edi+4) 0/imm32
 8713     0f 8d/jump-if->= $next-mu-token:end/disp32
 8714     # out->start = &in->data[in->read]
 8715     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
 8716     89/<- *edi 0/r32/eax
 8717     # var curr-byte/eax: byte = in->data[in->read]
 8718     31/xor-with %eax 0/r32/eax
 8719     8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
 8720     {
 8721 $next-mu-token:check-for-comma:
 8722       # if (curr-byte != ',') break
 8723       3d/compare-eax-and 0x2c/imm32/comma
 8724       75/jump-if-!= break/disp8
 8725       # ++in->read
 8726       ff 0/subop/increment *(esi+4)
 8727       # restart
 8728       e9/jump $next-mu-token:start/disp32
 8729     }
 8730     {
 8731 $next-mu-token:check-for-comment:
 8732       # if (curr-byte != '#') break
 8733       3d/compare-eax-and 0x23/imm32/pound
 8734       75/jump-if-!= break/disp8
 8735       # return eof
 8736       e9/jump $next-mu-token:done/disp32
 8737     }
 8738     {
 8739 $next-mu-token:check-for-string-literal:
 8740       # if (curr-byte != '"') break
 8741       3d/compare-eax-and 0x22/imm32/dquote
 8742       75/jump-if-!= break/disp8
 8743       (skip-string %esi)
 8744       # return
 8745       e9/jump $next-mu-token:done/disp32
 8746     }
 8747     {
 8748 $next-mu-token:check-for-open-paren:
 8749       # if (curr-byte != '(') break
 8750       3d/compare-eax-and 0x28/imm32/open-paren
 8751       75/jump-if-!= break/disp8
 8752       # ++in->read
 8753       ff 0/subop/increment *(esi+4)
 8754       # return
 8755       e9/jump $next-mu-token:done/disp32
 8756     }
 8757     {
 8758 $next-mu-token:check-for-close-paren:
 8759       # if (curr-byte != ')') break
 8760       3d/compare-eax-and 0x29/imm32/close-paren
 8761       75/jump-if-!= break/disp8
 8762       # ++in->read
 8763       ff 0/subop/increment *(esi+4)
 8764       # return
 8765       e9/jump $next-mu-token:done/disp32
 8766     }
 8767     {
 8768 $next-mu-token:regular-word-without-metadata:
 8769       # if (in->read >= in->write) break
 8770       # . ecx = in->read
 8771       8b/-> *(esi+4) 1/r32/ecx
 8772       # . if (ecx >= in->write) break
 8773       3b/compare<- *esi 1/r32/ecx
 8774       7d/jump-if->= break/disp8
 8775       # var c/eax: byte = in->data[in->read]
 8776       31/xor-with %eax 0/r32/eax
 8777       8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
 8778       # if (c == ' ') break
 8779       3d/compare-eax-and 0x20/imm32/space
 8780       74/jump-if-= break/disp8
 8781       # if (c == '\r') break
 8782       3d/compare-eax-and 0xd/imm32/carriage-return
 8783       74/jump-if-= break/disp8
 8784       # if (c == '\n') break
 8785       3d/compare-eax-and 0xa/imm32/newline
 8786       74/jump-if-= break/disp8
 8787       # if (c == '(') break
 8788       3d/compare-eax-and 0x28/imm32/open-paren
 8789       0f 84/jump-if-= break/disp32
 8790       # if (c == ')') break
 8791       3d/compare-eax-and 0x29/imm32/close-paren
 8792       0f 84/jump-if-= break/disp32
 8793       # if (c == ',') break
 8794       3d/compare-eax-and 0x2c/imm32/comma
 8795       0f 84/jump-if-= break/disp32
 8796       # ++in->read
 8797       ff 0/subop/increment *(esi+4)
 8798       #
 8799       e9/jump loop/disp32
 8800     }
 8801 $next-mu-token:done:
 8802     # out->end = &in->data[in->read]
 8803     8b/-> *(esi+4) 1/r32/ecx
 8804     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
 8805     89/<- *(edi+4) 0/r32/eax
 8806 $next-mu-token:end:
 8807     # . restore registers
 8808     5f/pop-to-edi
 8809     5e/pop-to-esi
 8810     59/pop-to-ecx
 8811     58/pop-to-eax
 8812     # . epilogue
 8813     89/<- %esp 5/r32/ebp
 8814     5d/pop-to-ebp
 8815     c3/return
 8816 
 8817 pos-or-insert-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
 8818     # . prologue
 8819     55/push-ebp
 8820     89/<- %ebp 4/r32/esp
 8821     # if (pos-slice(arr, s) != -1) return it
 8822     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
 8823     3d/compare-eax-and -1/imm32
 8824     75/jump-if-!= $pos-or-insert-slice:end/disp8
 8825 $pos-or-insert-slice:insert:
 8826     # var s2/eax: (handle array byte)
 8827     68/push 0/imm32
 8828     68/push 0/imm32
 8829     89/<- %eax 4/r32/esp
 8830     (slice-to-string Heap *(ebp+0xc) %eax)
 8831     # throw away alloc-id
 8832     (lookup *eax *(eax+4))  # => eax
 8833     (write-int *(ebp+8) %eax)
 8834     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
 8835 $pos-or-insert-slice:end:
 8836     # . reclaim locals
 8837     81 0/subop/add %esp 8/imm32
 8838     # . epilogue
 8839     89/<- %esp 5/r32/ebp
 8840     5d/pop-to-ebp
 8841     c3/return
 8842 
 8843 # return the index in an array of strings matching 's', -1 if not found
 8844 # index is denominated in elements, not bytes
 8845 pos-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
 8846     # . prologue
 8847     55/push-ebp
 8848     89/<- %ebp 4/r32/esp
 8849     # . save registers
 8850     51/push-ecx
 8851     52/push-edx
 8852     53/push-ebx
 8853     56/push-esi
 8854 #?     (write-buffered Stderr "pos-slice: ")
 8855 #?     (write-slice-buffered Stderr *(ebp+0xc))
 8856 #?     (write-buffered Stderr "\n")
 8857 #?     (flush Stderr)
 8858     # esi = arr
 8859     8b/-> *(ebp+8) 6/r32/esi
 8860     # var index/ecx: int = 0
 8861     b9/copy-to-ecx 0/imm32
 8862     # var curr/edx: (addr (addr array byte)) = arr->data
 8863     8d/copy-address *(esi+0xc) 2/r32/edx
 8864     # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write]
 8865     8b/-> *esi 3/r32/ebx
 8866     8d/copy-address *(esi+ebx+0xc) 3/r32/ebx
 8867     {
 8868 #?       (write-buffered Stderr "  ")
 8869 #?       (write-int32-hex-buffered Stderr %ecx)
 8870 #?       (write-buffered Stderr "\n")
 8871 #?       (flush Stderr)
 8872       # if (curr >= max) return -1
 8873       39/compare %edx 3/r32/ebx
 8874       b8/copy-to-eax -1/imm32
 8875       73/jump-if-addr>= $pos-slice:end/disp8
 8876       # if (slice-equal?(s, *curr)) break
 8877       (slice-equal? *(ebp+0xc) *edx)  # => eax
 8878       3d/compare-eax-and 0/imm32/false
 8879       75/jump-if-!= break/disp8
 8880       # ++index
 8881       41/increment-ecx
 8882       # curr += 4
 8883       81 0/subop/add %edx 4/imm32
 8884       #
 8885       eb/jump loop/disp8
 8886     }
 8887     # return index
 8888     89/<- %eax 1/r32/ecx
 8889 $pos-slice:end:
 8890 #?     (write-buffered Stderr "=> ")
 8891 #?     (write-int32-hex-buffered Stderr %eax)
 8892 #?     (write-buffered Stderr "\n")
 8893     # . restore registers
 8894     5e/pop-to-esi
 8895     5b/pop-to-ebx
 8896     5a/pop-to-edx
 8897     59/pop-to-ecx
 8898     # . epilogue
 8899     89/<- %esp 5/r32/ebp
 8900     5d/pop-to-ebp
 8901     c3/return
 8902 
 8903 test-parse-var-with-type:
 8904     # . prologue
 8905     55/push-ebp
 8906     89/<- %ebp 4/r32/esp
 8907     # (eax..ecx) = "x:"
 8908     b8/copy-to-eax "x:"/imm32
 8909     8b/-> *eax 1/r32/ecx
 8910     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8911     05/add-to-eax 4/imm32
 8912     # var slice/ecx: slice = {eax, ecx}
 8913     51/push-ecx
 8914     50/push-eax
 8915     89/<- %ecx 4/r32/esp
 8916     # _test-input-stream contains "int"
 8917     (clear-stream _test-input-stream)
 8918     (write _test-input-stream "int")
 8919     # var v/edx: (handle var)
 8920     68/push 0/imm32
 8921     68/push 0/imm32
 8922     89/<- %edx 4/r32/esp
 8923     #
 8924     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 8925     # var v-addr/edx: (addr var) = lookup(v)
 8926     (lookup *edx *(edx+4))  # => eax
 8927     89/<- %edx 0/r32/eax
 8928     # check v-addr->name
 8929     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 8930     (check-strings-equal %eax "x" "F - test-parse-var-with-type/name")
 8931     # check v-addr->type
 8932     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 8933     (check-ints-equal *eax 1 "F - test-parse-var-with-type/type:0")  # Type-tree-is-atom
 8934     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type/type:1")  # Type-tree-value
 8935     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type/type:2")  # Type-tree-right
 8936     # . epilogue
 8937     89/<- %esp 5/r32/ebp
 8938     5d/pop-to-ebp
 8939     c3/return
 8940 
 8941 test-parse-var-with-type-and-register:
 8942     # . prologue
 8943     55/push-ebp
 8944     89/<- %ebp 4/r32/esp
 8945     # (eax..ecx) = "x/eax:"
 8946     b8/copy-to-eax "x/eax:"/imm32
 8947     8b/-> *eax 1/r32/ecx
 8948     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8949     05/add-to-eax 4/imm32
 8950     # var slice/ecx: slice = {eax, ecx}
 8951     51/push-ecx
 8952     50/push-eax
 8953     89/<- %ecx 4/r32/esp
 8954     # _test-input-stream contains "int"
 8955     (clear-stream _test-input-stream)
 8956     (write _test-input-stream "int")
 8957     # var v/edx: (handle var)
 8958     68/push 0/imm32
 8959     68/push 0/imm32
 8960     89/<- %edx 4/r32/esp
 8961     #
 8962     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 8963     # var v-addr/edx: (addr var) = lookup(v)
 8964     (lookup *edx *(edx+4))  # => eax
 8965     89/<- %edx 0/r32/eax
 8966     # check v-addr->name
 8967     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 8968     (check-strings-equal %eax "x" "F - test-parse-var-with-type-and-register/name")
 8969     # check v-addr->register
 8970     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 8971     (check-strings-equal %eax "eax" "F - test-parse-var-with-type-and-register/register")
 8972     # check v-addr->type
 8973     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 8974     (check-ints-equal *eax 1 "F - test-parse-var-with-type-and-register/type:0")  # Type-tree-is-atom
 8975     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type-and-register/type:1")  # Type-tree-left
 8976     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type-and-register/type:2")  # Type-tree-right
 8977     # . epilogue
 8978     89/<- %esp 5/r32/ebp
 8979     5d/pop-to-ebp
 8980     c3/return
 8981 
 8982 test-parse-var-with-trailing-characters:
 8983     # . prologue
 8984     55/push-ebp
 8985     89/<- %ebp 4/r32/esp
 8986     # (eax..ecx) = "x:"
 8987     b8/copy-to-eax "x:"/imm32
 8988     8b/-> *eax 1/r32/ecx
 8989     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 8990     05/add-to-eax 4/imm32
 8991     # var slice/ecx: slice = {eax, ecx}
 8992     51/push-ecx
 8993     50/push-eax
 8994     89/<- %ecx 4/r32/esp
 8995     # _test-input-stream contains "int,"
 8996     (clear-stream _test-input-stream)
 8997     (write _test-input-stream "int,")
 8998     # var v/edx: (handle var)
 8999     68/push 0/imm32
 9000     68/push 0/imm32
 9001     89/<- %edx 4/r32/esp
 9002     #
 9003     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 9004     # var v-addr/edx: (addr var) = lookup(v)
 9005     (lookup *edx *(edx+4))  # => eax
 9006     89/<- %edx 0/r32/eax
 9007     # check v-addr->name
 9008     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 9009     (check-strings-equal %eax "x" "F - test-parse-var-with-trailing-characters/name")
 9010     # check v-addr->register
 9011     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-trailing-characters/register")  # Var-register
 9012     # check v-addr->type
 9013     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 9014     (check-ints-equal *eax 1 "F - test-parse-var-with-trailing-characters/type:0")  # Type-tree-is-atom
 9015     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-trailing-characters/type:1")  # Type-tree-left
 9016     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-trailing-characters/type:1")  # Type-tree-right
 9017     # . epilogue
 9018     89/<- %esp 5/r32/ebp
 9019     5d/pop-to-ebp
 9020     c3/return
 9021 
 9022 test-parse-var-with-register-and-trailing-characters:
 9023     # . prologue
 9024     55/push-ebp
 9025     89/<- %ebp 4/r32/esp
 9026     # (eax..ecx) = "x/eax:"
 9027     b8/copy-to-eax "x/eax:"/imm32
 9028     8b/-> *eax 1/r32/ecx
 9029     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9030     05/add-to-eax 4/imm32
 9031     # var slice/ecx: slice = {eax, ecx}
 9032     51/push-ecx
 9033     50/push-eax
 9034     89/<- %ecx 4/r32/esp
 9035     # _test-input-stream contains "int,"
 9036     (clear-stream _test-input-stream)
 9037     (write _test-input-stream "int,")
 9038     # var v/edx: (handle var)
 9039     68/push 0/imm32
 9040     68/push 0/imm32
 9041     89/<- %edx 4/r32/esp
 9042     #
 9043     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 9044     # var v-addr/edx: (addr var) = lookup(v)
 9045     (lookup *edx *(edx+4))  # => eax
 9046     89/<- %edx 0/r32/eax
 9047     # check v-addr->name
 9048     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 9049     (check-strings-equal %eax "x" "F - test-parse-var-with-register-and-trailing-characters/name")
 9050     # check v-addr->register
 9051     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 9052     (check-strings-equal %eax "eax" "F - test-parse-var-with-register-and-trailing-characters/register")
 9053     # check v-addr->type
 9054     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 9055     (check-ints-equal *eax 1 "F - test-parse-var-with-register-and-trailing-characters/type:0")  # Type-tree-is-atom
 9056     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-register-and-trailing-characters/type:1")  # Type-tree-left
 9057     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-register-and-trailing-characters/type:2")  # Type-tree-right
 9058     # . epilogue
 9059     89/<- %esp 5/r32/ebp
 9060     5d/pop-to-ebp
 9061     c3/return
 9062 
 9063 test-parse-var-with-compound-type:
 9064     # . prologue
 9065     55/push-ebp
 9066     89/<- %ebp 4/r32/esp
 9067     # (eax..ecx) = "x:"
 9068     b8/copy-to-eax "x:"/imm32
 9069     8b/-> *eax 1/r32/ecx
 9070     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9071     05/add-to-eax 4/imm32
 9072     # var slice/ecx: slice = {eax, ecx}
 9073     51/push-ecx
 9074     50/push-eax
 9075     89/<- %ecx 4/r32/esp
 9076     # _test-input-stream contains "(addr int)"
 9077     (clear-stream _test-input-stream)
 9078     (write _test-input-stream "(addr int)")
 9079     # var v/edx: (handle var)
 9080     68/push 0/imm32
 9081     68/push 0/imm32
 9082     89/<- %edx 4/r32/esp
 9083     #
 9084     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 9085     # var v-addr/edx: (addr var) = lookup(v)
 9086     (lookup *edx *(edx+4))  # => eax
 9087     89/<- %edx 0/r32/eax
 9088     # check v-addr->name
 9089     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 9090     (check-strings-equal %eax "x" "F - test-parse-var-with-compound-type/name")
 9091     # check v-addr->register
 9092     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-compound-type/register")  # Var-register
 9093     # - check v-addr->type
 9094     # var type/edx: (addr type-tree) = var->type
 9095     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 9096     89/<- %edx 0/r32/eax
 9097     # type is a non-atom
 9098     (check-ints-equal *edx 0 "F - test-parse-var-with-compound-type/type:0")  # Type-tree-is-atom
 9099     # type->left == atom(addr)
 9100     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
 9101     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:1")  # Type-tree-is-atom
 9102     (check-ints-equal *(eax+4) 2 "F - test-parse-var-with-compound-type/type:2")  # Type-tree-value
 9103     # type->right->left == atom(int)
 9104     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
 9105     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
 9106     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:3")  # Type-tree-is-atom
 9107     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-compound-type/type:4")  # Type-tree-value
 9108     # type->right->right == null
 9109     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-compound-type/type:5")  # Type-tree-right
 9110     # . epilogue
 9111     89/<- %esp 5/r32/ebp
 9112     5d/pop-to-ebp
 9113     c3/return
 9114 
 9115 # identifier starts with a letter or '$' or '_'
 9116 # no constraints at the moment on later letters
 9117 # all we really want to do so far is exclude '{', '}' and '->'
 9118 is-identifier?:  # in: (addr slice) -> result/eax: boolean
 9119     # . prologue
 9120     55/push-ebp
 9121     89/<- %ebp 4/r32/esp
 9122     # if (slice-empty?(in)) return false
 9123     (slice-empty? *(ebp+8))  # => eax
 9124     3d/compare-eax-and 0/imm32/false
 9125     75/jump-if-!= $is-identifier?:false/disp8
 9126     # var c/eax: byte = *in->start
 9127     8b/-> *(ebp+8) 0/r32/eax
 9128     8b/-> *eax 0/r32/eax
 9129     8a/copy-byte *eax 0/r32/AL
 9130     81 4/subop/and %eax 0xff/imm32
 9131     # if (c == '$') return true
 9132     3d/compare-eax-and 0x24/imm32/$
 9133     74/jump-if-= $is-identifier?:true/disp8
 9134     # if (c == '_') return true
 9135     3d/compare-eax-and 0x5f/imm32/_
 9136     74/jump-if-= $is-identifier?:true/disp8
 9137     # drop case
 9138     25/and-eax-with 0x5f/imm32
 9139     # if (c < 'A') return false
 9140     3d/compare-eax-and 0x41/imm32/A
 9141     7c/jump-if-< $is-identifier?:false/disp8
 9142     # if (c > 'Z') return false
 9143     3d/compare-eax-and 0x5a/imm32/Z
 9144     7f/jump-if-> $is-identifier?:false/disp8
 9145     # otherwise return true
 9146 $is-identifier?:true:
 9147     b8/copy-to-eax 1/imm32/true
 9148     eb/jump $is-identifier?:end/disp8
 9149 $is-identifier?:false:
 9150     b8/copy-to-eax 0/imm32/false
 9151 $is-identifier?:end:
 9152     # . epilogue
 9153     89/<- %esp 5/r32/ebp
 9154     5d/pop-to-ebp
 9155     c3/return
 9156 
 9157 test-is-identifier-dollar:
 9158     # . prologue
 9159     55/push-ebp
 9160     89/<- %ebp 4/r32/esp
 9161     # (eax..ecx) = "$a"
 9162     b8/copy-to-eax "$a"/imm32
 9163     8b/-> *eax 1/r32/ecx
 9164     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9165     05/add-to-eax 4/imm32
 9166     # var slice/ecx: slice = {eax, ecx}
 9167     51/push-ecx
 9168     50/push-eax
 9169     89/<- %ecx 4/r32/esp
 9170     #
 9171     (is-identifier? %ecx)
 9172     (check-ints-equal %eax 1 "F - test-is-identifier-dollar")
 9173     # . epilogue
 9174     89/<- %esp 5/r32/ebp
 9175     5d/pop-to-ebp
 9176     c3/return
 9177 
 9178 test-is-identifier-underscore:
 9179     # . prologue
 9180     55/push-ebp
 9181     89/<- %ebp 4/r32/esp
 9182     # (eax..ecx) = "_a"
 9183     b8/copy-to-eax "_a"/imm32
 9184     8b/-> *eax 1/r32/ecx
 9185     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9186     05/add-to-eax 4/imm32
 9187     # var slice/ecx: slice = {eax, ecx}
 9188     51/push-ecx
 9189     50/push-eax
 9190     89/<- %ecx 4/r32/esp
 9191     #
 9192     (is-identifier? %ecx)
 9193     (check-ints-equal %eax 1 "F - test-is-identifier-underscore")
 9194     # . epilogue
 9195     89/<- %esp 5/r32/ebp
 9196     5d/pop-to-ebp
 9197     c3/return
 9198 
 9199 test-is-identifier-a:
 9200     # . prologue
 9201     55/push-ebp
 9202     89/<- %ebp 4/r32/esp
 9203     # (eax..ecx) = "a$"
 9204     b8/copy-to-eax "a$"/imm32
 9205     8b/-> *eax 1/r32/ecx
 9206     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9207     05/add-to-eax 4/imm32
 9208     # var slice/ecx: slice = {eax, ecx}
 9209     51/push-ecx
 9210     50/push-eax
 9211     89/<- %ecx 4/r32/esp
 9212     #
 9213     (is-identifier? %ecx)
 9214     (check-ints-equal %eax 1 "F - test-is-identifier-a")
 9215     # . epilogue
 9216     89/<- %esp 5/r32/ebp
 9217     5d/pop-to-ebp
 9218     c3/return
 9219 
 9220 test-is-identifier-z:
 9221     # . prologue
 9222     55/push-ebp
 9223     89/<- %ebp 4/r32/esp
 9224     # (eax..ecx) = "z$"
 9225     b8/copy-to-eax "z$"/imm32
 9226     8b/-> *eax 1/r32/ecx
 9227     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9228     05/add-to-eax 4/imm32
 9229     # var slice/ecx: slice = {eax, ecx}
 9230     51/push-ecx
 9231     50/push-eax
 9232     89/<- %ecx 4/r32/esp
 9233     #
 9234     (is-identifier? %ecx)
 9235     (check-ints-equal %eax 1 "F - test-is-identifier-z")
 9236     # . epilogue
 9237     89/<- %esp 5/r32/ebp
 9238     5d/pop-to-ebp
 9239     c3/return
 9240 
 9241 test-is-identifier-A:
 9242     # . prologue
 9243     55/push-ebp
 9244     89/<- %ebp 4/r32/esp
 9245     # (eax..ecx) = "A$"
 9246     b8/copy-to-eax "A$"/imm32
 9247     8b/-> *eax 1/r32/ecx
 9248     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9249     05/add-to-eax 4/imm32
 9250     # var slice/ecx: slice = {eax, ecx}
 9251     51/push-ecx
 9252     50/push-eax
 9253     89/<- %ecx 4/r32/esp
 9254     #
 9255     (is-identifier? %ecx)
 9256     (check-ints-equal %eax 1 "F - test-is-identifier-A")
 9257     # . epilogue
 9258     89/<- %esp 5/r32/ebp
 9259     5d/pop-to-ebp
 9260     c3/return
 9261 
 9262 test-is-identifier-Z:
 9263     # . prologue
 9264     55/push-ebp
 9265     89/<- %ebp 4/r32/esp
 9266     # (eax..ecx) = "Z$"
 9267     b8/copy-to-eax "Z$"/imm32
 9268     8b/-> *eax 1/r32/ecx
 9269     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9270     05/add-to-eax 4/imm32
 9271     # var slice/ecx: slice = {eax, ecx}
 9272     51/push-ecx
 9273     50/push-eax
 9274     89/<- %ecx 4/r32/esp
 9275     #
 9276     (is-identifier? %ecx)
 9277     (check-ints-equal %eax 1 "F - test-is-identifier-Z")
 9278     # . epilogue
 9279     89/<- %esp 5/r32/ebp
 9280     5d/pop-to-ebp
 9281     c3/return
 9282 
 9283 test-is-identifier-at:
 9284     # character before 'A' is invalid
 9285     # . prologue
 9286     55/push-ebp
 9287     89/<- %ebp 4/r32/esp
 9288     # (eax..ecx) = "@a"
 9289     b8/copy-to-eax "@a"/imm32
 9290     8b/-> *eax 1/r32/ecx
 9291     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9292     05/add-to-eax 4/imm32
 9293     # var slice/ecx: slice = {eax, ecx}
 9294     51/push-ecx
 9295     50/push-eax
 9296     89/<- %ecx 4/r32/esp
 9297     #
 9298     (is-identifier? %ecx)
 9299     (check-ints-equal %eax 0 "F - test-is-identifier-@")
 9300     # . epilogue
 9301     89/<- %esp 5/r32/ebp
 9302     5d/pop-to-ebp
 9303     c3/return
 9304 
 9305 test-is-identifier-square-bracket:
 9306     # character after 'Z' is invalid
 9307     # . prologue
 9308     55/push-ebp
 9309     89/<- %ebp 4/r32/esp
 9310     # (eax..ecx) = "[a"
 9311     b8/copy-to-eax "[a"/imm32
 9312     8b/-> *eax 1/r32/ecx
 9313     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9314     05/add-to-eax 4/imm32
 9315     # var slice/ecx: slice = {eax, ecx}
 9316     51/push-ecx
 9317     50/push-eax
 9318     89/<- %ecx 4/r32/esp
 9319     #
 9320     (is-identifier? %ecx)
 9321     (check-ints-equal %eax 0 "F - test-is-identifier-@")
 9322     # . epilogue
 9323     89/<- %esp 5/r32/ebp
 9324     5d/pop-to-ebp
 9325     c3/return
 9326 
 9327 test-is-identifier-backtick:
 9328     # character before 'a' is invalid
 9329     # . prologue
 9330     55/push-ebp
 9331     89/<- %ebp 4/r32/esp
 9332     # (eax..ecx) = "`a"
 9333     b8/copy-to-eax "`a"/imm32
 9334     8b/-> *eax 1/r32/ecx
 9335     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9336     05/add-to-eax 4/imm32
 9337     # var slice/ecx: slice = {eax, ecx}
 9338     51/push-ecx
 9339     50/push-eax
 9340     89/<- %ecx 4/r32/esp
 9341     #
 9342     (is-identifier? %ecx)
 9343     (check-ints-equal %eax 0 "F - test-is-identifier-backtick")
 9344     # . epilogue
 9345     89/<- %esp 5/r32/ebp
 9346     5d/pop-to-ebp
 9347     c3/return
 9348 
 9349 test-is-identifier-curly-brace-open:
 9350     # character after 'z' is invalid; also used for blocks
 9351     # . prologue
 9352     55/push-ebp
 9353     89/<- %ebp 4/r32/esp
 9354     # (eax..ecx) = "{a"
 9355     b8/copy-to-eax "{a"/imm32
 9356     8b/-> *eax 1/r32/ecx
 9357     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9358     05/add-to-eax 4/imm32
 9359     # var slice/ecx: slice = {eax, ecx}
 9360     51/push-ecx
 9361     50/push-eax
 9362     89/<- %ecx 4/r32/esp
 9363     #
 9364     (is-identifier? %ecx)
 9365     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open")
 9366     # . epilogue
 9367     89/<- %esp 5/r32/ebp
 9368     5d/pop-to-ebp
 9369     c3/return
 9370 
 9371 test-is-identifier-curly-brace-close:
 9372     # . prologue
 9373     55/push-ebp
 9374     89/<- %ebp 4/r32/esp
 9375     # (eax..ecx) = "}a"
 9376     b8/copy-to-eax "}a"/imm32
 9377     8b/-> *eax 1/r32/ecx
 9378     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9379     05/add-to-eax 4/imm32
 9380     # var slice/ecx: slice = {eax, ecx}
 9381     51/push-ecx
 9382     50/push-eax
 9383     89/<- %ecx 4/r32/esp
 9384     #
 9385     (is-identifier? %ecx)
 9386     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close")
 9387     # . epilogue
 9388     89/<- %esp 5/r32/ebp
 9389     5d/pop-to-ebp
 9390     c3/return
 9391 
 9392 test-is-identifier-hyphen:
 9393     # disallow leading '-' since '->' has special meaning
 9394     # . prologue
 9395     55/push-ebp
 9396     89/<- %ebp 4/r32/esp
 9397     # (eax..ecx) = "-a"
 9398     b8/copy-to-eax "-a"/imm32
 9399     8b/-> *eax 1/r32/ecx
 9400     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9401     05/add-to-eax 4/imm32
 9402     # var slice/ecx: slice = {eax, ecx}
 9403     51/push-ecx
 9404     50/push-eax
 9405     89/<- %ecx 4/r32/esp
 9406     #
 9407     (is-identifier? %ecx)
 9408     (check-ints-equal %eax 0 "F - test-is-identifier-hyphen")
 9409     # . epilogue
 9410     89/<- %esp 5/r32/ebp
 9411     5d/pop-to-ebp
 9412     c3/return
 9413 
 9414 populate-mu-function-body:  # in: (addr buffered-file), out: (addr function), vars: (addr stack live-var), err: (addr buffered-file), ed: (addr exit-descriptor)
 9415     # . prologue
 9416     55/push-ebp
 9417     89/<- %ebp 4/r32/esp
 9418     # . save registers
 9419     50/push-eax
 9420     56/push-esi
 9421     57/push-edi
 9422     # esi = in
 9423     8b/-> *(ebp+8) 6/r32/esi
 9424     # edi = out
 9425     8b/-> *(ebp+0xc) 7/r32/edi
 9426     # initialize some global state
 9427     c7 0/subop/copy *Curr-block-depth 1/imm32
 9428     # parse-mu-block(in, vars, out, out->body)
 9429     8d/copy-address *(edi+0x18) 0/r32/eax  # Function-body
 9430     (parse-mu-block %esi *(ebp+0x10) %edi %eax *(ebp+0x14) *(ebp+0x18))
 9431 $populate-mu-function-body:end:
 9432     # . restore registers
 9433     5f/pop-to-edi
 9434     5e/pop-to-esi
 9435     58/pop-to-eax
 9436     # . epilogue
 9437     89/<- %esp 5/r32/ebp
 9438     5d/pop-to-ebp
 9439     c3/return
 9440 
 9441 # parses a block, assuming that the leading '{' has already been read by the caller
 9442 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)
 9443     # pseudocode:
 9444     #   var line: (stream byte 512)
 9445     #   var word-slice: slice
 9446     #   allocate(Heap, Stmt-size, out)
 9447     #   var out-addr: (addr block) = lookup(*out)
 9448     #   out-addr->tag = 0/block
 9449     #   out-addr->var = some unique name
 9450     #   push(vars, {out-addr->var, false})
 9451     #   while true                                  # line loop
 9452     #     clear-stream(line)
 9453     #     read-line-buffered(in, line)
 9454     #     if (line->write == 0) break               # end of file
 9455     #     word-slice = next-mu-token(line)
 9456     #     if slice-empty?(word-slice)               # end of line
 9457     #       continue
 9458     #     else if slice-starts-with?(word-slice, "#")
 9459     #       continue
 9460     #     else if slice-equal?(word-slice, "{")
 9461     #       assert(no-tokens-in(line))
 9462     #       block = parse-mu-block(in, vars, fn)
 9463     #       append-to-block(out-addr, block)
 9464     #     else if slice-equal?(word-slice, "}")
 9465     #       break
 9466     #     else if slice-ends-with?(word-slice, ":")
 9467     #       # TODO: error-check the rest of 'line'
 9468     #       --word-slice->end to skip ':'
 9469     #       named-block = parse-mu-named-block(word-slice, in, vars, fn)
 9470     #       append-to-block(out-addr, named-block)
 9471     #     else if slice-equal?(word-slice, "var")
 9472     #       var-def = parse-mu-var-def(line, vars, fn)
 9473     #       append-to-block(out-addr, var-def)
 9474     #     else
 9475     #       stmt = parse-mu-stmt(line, vars, fn)
 9476     #       append-to-block(out-addr, stmt)
 9477     #   pop(vars)
 9478     #
 9479     # . prologue
 9480     55/push-ebp
 9481     89/<- %ebp 4/r32/esp
 9482     # . save registers
 9483     50/push-eax
 9484     51/push-ecx
 9485     52/push-edx
 9486     53/push-ebx
 9487     57/push-edi
 9488     # var line/ecx: (stream byte 512)
 9489     81 5/subop/subtract %esp 0x200/imm32
 9490     68/push 0x200/imm32/size
 9491     68/push 0/imm32/read
 9492     68/push 0/imm32/write
 9493     89/<- %ecx 4/r32/esp
 9494     # var word-slice/edx: slice
 9495     68/push 0/imm32/end
 9496     68/push 0/imm32/start
 9497     89/<- %edx 4/r32/esp
 9498     # allocate into out
 9499     (allocate Heap *Stmt-size *(ebp+0x14))
 9500     # var out-addr/edi: (addr block) = lookup(*out)
 9501     8b/-> *(ebp+0x14) 7/r32/edi
 9502     (lookup *edi *(edi+4))  # => eax
 9503     89/<- %edi 0/r32/eax
 9504     # out-addr->tag is 0 (block) by default
 9505     # set out-addr->var
 9506     8d/copy-address *(edi+0xc) 0/r32/eax  # Block-var
 9507     (new-block-name *(ebp+0x10) %eax)
 9508     # push(vars, out-addr->var)
 9509     (push *(ebp+0xc) *(edi+0xc))  # Block-var
 9510     (push *(ebp+0xc) *(edi+0x10))  # Block-var
 9511     (push *(ebp+0xc) 0)  # false
 9512     # increment *Curr-block-depth
 9513     ff 0/subop/increment *Curr-block-depth
 9514     {
 9515 $parse-mu-block:line-loop:
 9516       # line = read-line-buffered(in)
 9517       (clear-stream %ecx)
 9518       (read-line-buffered *(ebp+8) %ecx)
 9519 #?       (write-buffered Stderr "line: ")
 9520 #?       (write-stream-data Stderr %ecx)
 9521 #? #?       (write-buffered Stderr Newline)  # line has its own newline
 9522 #?       (flush Stderr)
 9523 #?       (rewind-stream %ecx)
 9524       # if (line->write == 0) break
 9525       81 7/subop/compare *ecx 0/imm32
 9526       0f 84/jump-if-= break/disp32
 9527 #?       (write-buffered Stderr "vars:\n")
 9528 #?       (dump-vars *(ebp+0xc))
 9529       # word-slice = next-mu-token(line)
 9530       (next-mu-token %ecx %edx)
 9531 #?       (write-buffered Stderr "word: ")
 9532 #?       (write-slice-buffered Stderr %edx)
 9533 #?       (write-buffered Stderr Newline)
 9534 #?       (flush Stderr)
 9535       # if slice-empty?(word-slice) continue
 9536       (slice-empty? %edx)
 9537       3d/compare-eax-and 0/imm32/false
 9538       0f 85/jump-if-!= loop/disp32
 9539       # if (slice-starts-with?(word-slice, '#') continue
 9540       # . eax = *word-slice->start
 9541       8b/-> *edx 0/r32/eax
 9542       8a/copy-byte *eax 0/r32/AL
 9543       81 4/subop/and %eax 0xff/imm32
 9544       # . if (eax == '#') continue
 9545       3d/compare-eax-and 0x23/imm32/hash
 9546       0f 84/jump-if-= loop/disp32
 9547       # if slice-equal?(word-slice, "{")
 9548       {
 9549 $parse-mu-block:check-for-block:
 9550         (slice-equal? %edx "{")
 9551         3d/compare-eax-and 0/imm32/false
 9552         74/jump-if-= break/disp8
 9553         (check-no-tokens-left %ecx)
 9554         # parse new block and append
 9555         # . var tmp/eax: (handle block)
 9556         68/push 0/imm32
 9557         68/push 0/imm32
 9558         89/<- %eax 4/r32/esp
 9559         # .
 9560         (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 9561         (append-to-block Heap %edi  *eax *(eax+4))
 9562         # . reclaim tmp
 9563         81 0/subop/add %esp 8/imm32
 9564         # .
 9565         e9/jump $parse-mu-block:line-loop/disp32
 9566       }
 9567       # if slice-equal?(word-slice, "}") break
 9568 $parse-mu-block:check-for-end:
 9569       (slice-equal? %edx "}")
 9570       3d/compare-eax-and 0/imm32/false
 9571       0f 85/jump-if-!= break/disp32
 9572       # if slice-ends-with?(word-slice, ":") parse named block and append
 9573       {
 9574 $parse-mu-block:check-for-named-block:
 9575         # . eax = *(word-slice->end-1)
 9576         8b/-> *(edx+4) 0/r32/eax
 9577         48/decrement-eax
 9578         8a/copy-byte *eax 0/r32/AL
 9579         81 4/subop/and %eax 0xff/imm32
 9580         # . if (eax != ':') break
 9581         3d/compare-eax-and 0x3a/imm32/colon
 9582         0f 85/jump-if-!= break/disp32
 9583         # TODO: error-check the rest of 'line'
 9584         #
 9585         # skip ':'
 9586         ff 1/subop/decrement *(edx+4)  # Slice-end
 9587         # var tmp/eax: (handle block)
 9588         68/push 0/imm32
 9589         68/push 0/imm32
 9590         89/<- %eax 4/r32/esp
 9591         #
 9592         (parse-mu-named-block %edx *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 9593         (append-to-block Heap %edi  *eax *(eax+4))
 9594         # reclaim tmp
 9595         81 0/subop/add %esp 8/imm32
 9596         #
 9597         e9/jump $parse-mu-block:line-loop/disp32
 9598       }
 9599       # if slice-equal?(word-slice, "var")
 9600       {
 9601 $parse-mu-block:check-for-var:
 9602         (slice-equal? %edx "var")
 9603         3d/compare-eax-and 0/imm32/false
 9604         74/jump-if-= break/disp8
 9605         # var tmp/eax: (handle block)
 9606         68/push 0/imm32
 9607         68/push 0/imm32
 9608         89/<- %eax 4/r32/esp
 9609         #
 9610         (parse-mu-var-def %ecx *(ebp+0xc) %eax *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
 9611         (append-to-block Heap %edi  *eax *(eax+4))
 9612         # reclaim tmp
 9613         81 0/subop/add %esp 8/imm32
 9614         #
 9615         e9/jump $parse-mu-block:line-loop/disp32
 9616       }
 9617 $parse-mu-block:regular-stmt:
 9618       # otherwise
 9619       # var tmp/eax: (handle block)
 9620       68/push 0/imm32
 9621       68/push 0/imm32
 9622       89/<- %eax 4/r32/esp
 9623       #
 9624       (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 9625       (append-to-block Heap %edi  *eax *(eax+4))
 9626       # reclaim tmp
 9627       81 0/subop/add %esp 8/imm32
 9628       #
 9629       e9/jump loop/disp32
 9630     } # end line loop
 9631     (clean-up-blocks *(ebp+0xc) *Curr-block-depth *(ebp+0x10))
 9632     # decrement *Curr-block-depth
 9633     ff 1/subop/decrement *Curr-block-depth
 9634     # pop(vars)
 9635     (pop *(ebp+0xc))  # => eax
 9636     (pop *(ebp+0xc))  # => eax
 9637     (pop *(ebp+0xc))  # => eax
 9638 $parse-mu-block:end:
 9639     # . reclaim locals
 9640     81 0/subop/add %esp 0x214/imm32
 9641     # . restore registers
 9642     5f/pop-to-edi
 9643     5b/pop-to-ebx
 9644     5a/pop-to-edx
 9645     59/pop-to-ecx
 9646     58/pop-to-eax
 9647     # . epilogue
 9648     89/<- %esp 5/r32/ebp
 9649     5d/pop-to-ebp
 9650     c3/return
 9651 
 9652 $parse-mu-block:abort:
 9653     # error("'{' or '}' should be on its own line, but got '")
 9654     (write-buffered *(ebp+0x18) "'{' or '}' should be on its own line, but got '")
 9655     (rewind-stream %ecx)
 9656     (write-stream-data *(ebp+0x18) %ecx)
 9657     (write-buffered *(ebp+0x18) "'\n")
 9658     (flush *(ebp+0x18))
 9659     (stop *(ebp+0x1c) 1)
 9660     # never gets here
 9661 
 9662 new-block-name:  # fn: (addr function), out: (addr handle var)
 9663     # . prologue
 9664     55/push-ebp
 9665     89/<- %ebp 4/r32/esp
 9666     # . save registers
 9667     50/push-eax
 9668     51/push-ecx
 9669     52/push-edx
 9670     # var n/ecx: int = len(fn->name) + 10 for an int + 2 for '$:'
 9671     8b/-> *(ebp+8) 0/r32/eax
 9672     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9673     8b/-> *eax 0/r32/eax  # String-size
 9674     05/add-to-eax 0xd/imm32  # 10 + 2 for '$:'
 9675     89/<- %ecx 0/r32/eax
 9676     # var name/edx: (stream byte n)
 9677     29/subtract-from %esp 1/r32/ecx
 9678     ff 6/subop/push %ecx
 9679     68/push 0/imm32/read
 9680     68/push 0/imm32/write
 9681     89/<- %edx 4/r32/esp
 9682     (clear-stream %edx)
 9683     # eax = fn->name
 9684     8b/-> *(ebp+8) 0/r32/eax
 9685     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9686     # construct result using Next-block-index (and increment it)
 9687     (write %edx "$")
 9688     (write %edx %eax)
 9689     (write %edx ":")
 9690     (write-int32-hex %edx *Next-block-index)
 9691     ff 0/subop/increment *Next-block-index
 9692     # var s/eax: slice = {name->data, name->data + name->write}  (clobbering edx)
 9693     # . eax = name->write
 9694     8b/-> *edx 0/r32/eax
 9695     # . edx = name->data
 9696     8d/copy-address *(edx+0xc) 2/r32/edx
 9697     # . eax = name->write + name->data
 9698     01/add-to %eax 2/r32/edx
 9699     # . push {edx, eax}
 9700     ff 6/subop/push %eax
 9701     ff 6/subop/push %edx
 9702     89/<- %eax 4/r32/esp
 9703     # out = new literal(s)
 9704     (new-literal Heap %eax *(ebp+0xc))
 9705 #?     8b/-> *(ebp+0xc) 0/r32/eax
 9706 #?     (write-buffered Stderr "type allocid in caller after new-literal: ")
 9707 #?     (write-int32-hex-buffered Stderr *(eax+8))
 9708 #?     (write-buffered Stderr " for var ")
 9709 #?     (write-int32-hex-buffered Stderr %eax)
 9710 #?     (write-buffered Stderr Newline)
 9711 #?     (flush Stderr)
 9712 $new-block-name:end:
 9713     # . reclaim locals
 9714     81 0/subop/add %ecx 0xc/imm32  # name.{read/write/len}
 9715     81 0/subop/add %ecx 8/imm32  # slice
 9716     01/add-to %esp 1/r32/ecx
 9717     # . restore registers
 9718     5a/pop-to-edx
 9719     59/pop-to-ecx
 9720     58/pop-to-eax
 9721     # . epilogue
 9722     89/<- %esp 5/r32/ebp
 9723     5d/pop-to-ebp
 9724     c3/return
 9725 
 9726 check-no-tokens-left:  # line: (addr stream byte)
 9727     # . prologue
 9728     55/push-ebp
 9729     89/<- %ebp 4/r32/esp
 9730     # . save registers
 9731     50/push-eax
 9732     51/push-ecx
 9733     # var s/ecx: slice
 9734     68/push 0/imm32/end
 9735     68/push 0/imm32/start
 9736     89/<- %ecx 4/r32/esp
 9737     #
 9738     (next-mu-token *(ebp+8) %ecx)
 9739     # if slice-empty?(s) return
 9740     (slice-empty? %ecx)
 9741     3d/compare-eax-and 0/imm32/false
 9742     75/jump-if-!= $check-no-tokens-left:end/disp8
 9743     # if (slice-starts-with?(s, '#') return
 9744     # . eax = *s->start
 9745     8b/-> *edx 0/r32/eax
 9746     8a/copy-byte *eax 0/r32/AL
 9747     81 4/subop/and %eax 0xff/imm32
 9748     # . if (eax == '#') continue
 9749     3d/compare-eax-and 0x23/imm32/hash
 9750     74/jump-if-= $check-no-tokens-left:end/disp8
 9751     # abort
 9752     (write-buffered Stderr "'{' or '}' should be on its own line, but got '")
 9753     (rewind-stream %ecx)
 9754     (write-stream 2 %ecx)
 9755     (write-buffered Stderr "'\n")
 9756     (flush Stderr)
 9757     # . syscall(exit, 1)
 9758     bb/copy-to-ebx  1/imm32
 9759     e8/call syscall_exit/disp32
 9760     # never gets here
 9761 $check-no-tokens-left:end:
 9762     # . reclaim locals
 9763     81 0/subop/add %esp 8/imm32
 9764     # . restore registers
 9765     59/pop-to-ecx
 9766     58/pop-to-eax
 9767     # . epilogue
 9768     89/<- %esp 5/r32/ebp
 9769     5d/pop-to-ebp
 9770     c3/return
 9771 
 9772 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)
 9773     # pseudocode:
 9774     #   var v: (handle var)
 9775     #   new-literal(name, v)
 9776     #   push(vars, {v, false})
 9777     #   parse-mu-block(in, vars, fn, out)
 9778     #   pop(vars)
 9779     #   out->tag = block
 9780     #   out->var = v
 9781     #
 9782     # . prologue
 9783     55/push-ebp
 9784     89/<- %ebp 4/r32/esp
 9785     # . save registers
 9786     50/push-eax
 9787     51/push-ecx
 9788     57/push-edi
 9789     # var v/ecx: (handle var)
 9790     68/push 0/imm32
 9791     68/push 0/imm32
 9792     89/<- %ecx 4/r32/esp
 9793     #
 9794     (new-literal Heap *(ebp+8) %ecx)
 9795     # push(vars, v)
 9796     (push *(ebp+0x10) *ecx)
 9797     (push *(ebp+0x10) *(ecx+4))
 9798     (push *(ebp+0x10) 0)  # false
 9799     #
 9800     (parse-mu-block *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20))
 9801     # pop v off vars
 9802     (pop *(ebp+0x10))  # => eax
 9803     (pop *(ebp+0x10))  # => eax
 9804     (pop *(ebp+0x10))  # => eax
 9805     # var out-addr/edi: (addr stmt) = lookup(*out)
 9806     8b/-> *(ebp+0x18) 7/r32/edi
 9807     (lookup *edi *(edi+4))  # => eax
 9808     89/<- %edi 0/r32/eax
 9809     # out-addr->tag = named-block
 9810     c7 0/subop/copy *edi 0/imm32/block  # Stmt-tag
 9811     # out-addr->var = v
 9812     8b/-> *ecx 0/r32/eax
 9813     89/<- *(edi+0xc) 0/r32/eax  # Block-var
 9814     8b/-> *(ecx+4) 0/r32/eax
 9815     89/<- *(edi+0x10) 0/r32/eax  # Block-var
 9816 $parse-mu-named-block:end:
 9817     # . reclaim locals
 9818     81 0/subop/add %esp 8/imm32
 9819     # . restore registers
 9820     5f/pop-to-edi
 9821     59/pop-to-ecx
 9822     58/pop-to-eax
 9823     # . epilogue
 9824     89/<- %esp 5/r32/ebp
 9825     5d/pop-to-ebp
 9826     c3/return
 9827 
 9828 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)
 9829     # . prologue
 9830     55/push-ebp
 9831     89/<- %ebp 4/r32/esp
 9832     # . save registers
 9833     50/push-eax
 9834     51/push-ecx
 9835     52/push-edx
 9836     53/push-ebx
 9837     57/push-edi
 9838     # edi = out
 9839     8b/-> *(ebp+0x10) 7/r32/edi
 9840     # var word-slice/ecx: slice
 9841     68/push 0/imm32/end
 9842     68/push 0/imm32/start
 9843     89/<- %ecx 4/r32/esp
 9844     # var v/edx: (handle var)
 9845     68/push 0/imm32
 9846     68/push 0/imm32
 9847     89/<- %edx 4/r32/esp
 9848     # v = parse-var-with-type(next-mu-token(line))
 9849     (next-mu-token *(ebp+8) %ecx)
 9850     (parse-var-with-type %ecx *(ebp+8) %edx *(ebp+0x18) *(ebp+0x1c))
 9851     # var v-addr/eax: (addr var)
 9852     (lookup *edx *(edx+4))  # => eax
 9853     # v->block-depth = *Curr-block-depth
 9854     8b/-> *Curr-block-depth 3/r32/ebx
 9855     89/<- *(eax+0x10) 3/r32/ebx  # Var-block-depth
 9856     # either v has no register and there's no more to this line
 9857     8b/-> *(eax+0x18) 0/r32/eax  # Var-register
 9858     3d/compare-eax-and 0/imm32
 9859     {
 9860       75/jump-if-!= break/disp8
 9861       # TODO: disallow vars of type 'byte' on the stack
 9862       # ensure that there's nothing else on this line
 9863       (next-mu-token *(ebp+8) %ecx)
 9864       (slice-empty? %ecx)  # => eax
 9865       3d/compare-eax-and 0/imm32/false
 9866       0f 84/jump-if-= $parse-mu-var-def:error2/disp32
 9867       #
 9868       (new-var-def Heap  *edx *(edx+4)  %edi)
 9869       e9/jump $parse-mu-var-def:update-vars/disp32
 9870     }
 9871     # or v has a register and there's more to this line
 9872     {
 9873       0f 84/jump-if-= break/disp32
 9874       # TODO: disallow vars of type 'byte' in registers 'esi' or 'edi'
 9875       # TODO: vars of type 'byte' should only be initialized by clearing to 0
 9876       # ensure that the next word is '<-'
 9877       (next-mu-token *(ebp+8) %ecx)
 9878       (slice-equal? %ecx "<-")  # => eax
 9879       3d/compare-eax-and 0/imm32/false
 9880       0f 84/jump-if-= $parse-mu-var-def:error1/disp32
 9881       #
 9882       (new-reg-var-def Heap  *edx *(edx+4)  %edi)
 9883       (lookup *edi *(edi+4))  # => eax
 9884       (add-operation-and-inputs-to-stmt %eax *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 9885     }
 9886 $parse-mu-var-def:update-vars:
 9887     # push 'v' at end of function
 9888     (push *(ebp+0xc) *edx)
 9889     (push *(ebp+0xc) *(edx+4))
 9890     (push *(ebp+0xc) 0)  # Live-var-register-spilled is unused during parsing
 9891 $parse-mu-var-def:end:
 9892     # . reclaim locals
 9893     81 0/subop/add %esp 0x10/imm32
 9894     # . restore registers
 9895     5f/pop-to-edi
 9896     5b/pop-to-ebx
 9897     5a/pop-to-edx
 9898     59/pop-to-ecx
 9899     58/pop-to-eax
 9900     # . epilogue
 9901     89/<- %esp 5/r32/ebp
 9902     5d/pop-to-ebp
 9903     c3/return
 9904 
 9905 $parse-mu-var-def:error1:
 9906     (rewind-stream *(ebp+8))
 9907     # error("register variable requires a valid instruction to initialize but got '" line "'\n")
 9908     (write-buffered *(ebp+0x18) "register variable requires a valid instruction to initialize but got '")
 9909     (flush *(ebp+0x18))
 9910     (write-stream-data *(ebp+0x18) *(ebp+8))
 9911     (write-buffered *(ebp+0x18) "'\n")
 9912     (flush *(ebp+0x18))
 9913     (stop *(ebp+0x1c) 1)
 9914     # never gets here
 9915 
 9916 $parse-mu-var-def:error2:
 9917     (rewind-stream *(ebp+8))
 9918     # error("fn " fn ": var " var ": variables on the stack can't take an initializer\n")
 9919     (write-buffered *(ebp+0x18) "fn ")
 9920     8b/-> *(ebp+0x14) 0/r32/eax
 9921     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9922     (write-buffered *(ebp+0x18) %eax)
 9923     (write-buffered *(ebp+0x18) ": var ")
 9924     # var v-addr/eax: (addr var) = lookup(v)
 9925     (lookup *edx *(edx+4))  # => eax
 9926     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9927     (write-buffered *(ebp+0x18) %eax)
 9928     (write-buffered *(ebp+0x18) ": variables on the stack can't take an initializer\n")
 9929     (flush *(ebp+0x18))
 9930     (stop *(ebp+0x1c) 1)
 9931     # never gets here
 9932 
 9933 test-parse-mu-var-def:
 9934     # 'var n: int'
 9935     # . prologue
 9936     55/push-ebp
 9937     89/<- %ebp 4/r32/esp
 9938     # setup
 9939     (clear-stream _test-input-stream)
 9940     (write _test-input-stream "n: int\n")  # caller has consumed the 'var'
 9941     c7 0/subop/copy *Curr-block-depth 1/imm32
 9942     # var out/esi: (handle stmt)
 9943     68/push 0/imm32
 9944     68/push 0/imm32
 9945     89/<- %esi 4/r32/esp
 9946     # var vars/ecx: (stack (addr var) 16)
 9947     81 5/subop/subtract %esp 0xc0/imm32
 9948     68/push 0xc0/imm32/size
 9949     68/push 0/imm32/top
 9950     89/<- %ecx 4/r32/esp
 9951     (clear-stack %ecx)
 9952     # convert
 9953     (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0)
 9954     # var out-addr/esi: (addr stmt)
 9955     (lookup *esi *(esi+4))  # => eax
 9956     89/<- %esi 0/r32/eax
 9957     #
 9958     (check-ints-equal *esi 2 "F - test-parse-mu-var-def/tag")  # Stmt-tag is var-def
 9959     # var v/ecx: (addr var) = lookup(out->var)
 9960     (lookup *(esi+4) *(esi+8))  # Vardef-var Vardef-var => eax
 9961     89/<- %ecx 0/r32/eax
 9962     # v->name
 9963     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 9964     (check-strings-equal %eax "n" "F - test-parse-mu-var-def/var-name")
 9965     # v->register
 9966     (check-ints-equal *(ecx+0x18) 0 "F - test-parse-mu-var-def/var-register")  # Var-register
 9967     # v->block-depth
 9968     (check-ints-equal *(ecx+0x10) 1 "F - test-parse-mu-var-def/output-block-depth")  # Var-block-depth
 9969     # v->type == int
 9970     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 9971     (check-ints-equal *eax 1 "F - test-parse-mu-var-def/var-type:0")  # Type-tree-is-atom
 9972     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-var-def/var-type:1")  # Type-tree-value
 9973     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-var-def/var-type:2")  # Type-tree-right
 9974     # . epilogue
 9975     89/<- %esp 5/r32/ebp
 9976     5d/pop-to-ebp
 9977     c3/return
 9978 
 9979 test-parse-mu-reg-var-def:
 9980     # 'var n/eax: int <- copy 0'
 9981     # . prologue
 9982     55/push-ebp
 9983     89/<- %ebp 4/r32/esp
 9984     # setup
 9985     (clear-stream _test-input-stream)
 9986     (write _test-input-stream "n/eax: int <- copy 0\n")  # caller has consumed the 'var'
 9987     c7 0/subop/copy *Curr-block-depth 1/imm32
 9988     # var out/esi: (handle stmt)
 9989     68/push 0/imm32
 9990     68/push 0/imm32
 9991     89/<- %esi 4/r32/esp
 9992     # var vars/ecx: (stack (addr var) 16)
 9993     81 5/subop/subtract %esp 0xc0/imm32
 9994     68/push 0xc0/imm32/size
 9995     68/push 0/imm32/top
 9996     89/<- %ecx 4/r32/esp
 9997     (clear-stack %ecx)
 9998     # convert
 9999     (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0)
10000     # var out-addr/esi: (addr stmt)
10001     (lookup *esi *(esi+4))  # => eax
10002     89/<- %esi 0/r32/eax
10003     #
10004     (check-ints-equal *esi 3 "F - test-parse-mu-reg-var-def/tag")  # Stmt-tag is reg-var-def
10005     # var v/ecx: (addr var) = lookup(out->outputs->value)
10006     # . eax: (addr stmt-var) = lookup(out->outputs)
10007     (lookup *(esi+0x14) *(esi+0x18))  # Regvardef-outputs Regvardef-outputs => eax
10008     # .
10009     (check-ints-equal *(eax+8) 0 "F - test-parse-mu-reg-var-def/single-output")  # Stmt-var-next
10010     # . eax: (addr var) = lookup(eax->value)
10011     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10012     # . ecx = eax
10013     89/<- %ecx 0/r32/eax
10014     # v->name
10015     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
10016     (check-strings-equal %eax "n" "F - test-parse-mu-reg-var-def/output-name")  # Var-name
10017     # v->register
10018     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
10019     (check-strings-equal %eax "eax" "F - test-parse-mu-reg-var-def/output-register")
10020     # v->block-depth
10021     (check-ints-equal *(ecx+0x10) 1 "F - test-parse-mu-reg-var-def/output-block-depth")  # Var-block-depth
10022     # v->type == int
10023     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
10024     (check-ints-equal *eax 1 "F - test-parse-mu-reg-var-def/output-type:0")  # Type-tree-is-atom
10025     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-reg-var-def/output-type:1")  # Type-tree-value
10026     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-reg-var-def/output-type:2")  # Type-tree-right
10027     # . epilogue
10028     89/<- %esp 5/r32/ebp
10029     5d/pop-to-ebp
10030     c3/return
10031 
10032 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)
10033     # Carefully push any outputs on the vars stack _after_ reading the inputs
10034     # that may conflict with them.
10035     #
10036     # The only situation in which outputs are pushed here (when it's not a
10037     # 'var' vardef stmt), and so can possibly conflict with inputs, is if the
10038     # output is a function output.
10039     #
10040     # pseudocode:
10041     #   var name: slice
10042     #   allocate(Heap, Stmt-size, out)
10043     #   var out-addr: (addr stmt) = lookup(*out)
10044     #   out-addr->tag = stmt
10045     #   if stmt-has-outputs?(line)
10046     #     while true
10047     #       name = next-mu-token(line)
10048     #       if (name == '<-') break
10049     #       assert(is-identifier?(name))
10050     #       var v: (handle var) = lookup-var-or-find-in-fn-outputs(name, vars, fn)
10051     #       out-addr->outputs = append(v, out-addr->outputs)
10052     #   add-operation-and-inputs-to-stmt(out-addr, line, vars)
10053     #   for output in stmt->outputs:
10054     #     maybe-define-var(output, vars)
10055     #
10056     # . prologue
10057     55/push-ebp
10058     89/<- %ebp 4/r32/esp
10059     # . save registers
10060     50/push-eax
10061     51/push-ecx
10062     52/push-edx
10063     53/push-ebx
10064     57/push-edi
10065     # var name/ecx: slice
10066     68/push 0/imm32/end
10067     68/push 0/imm32/start
10068     89/<- %ecx 4/r32/esp
10069     # var is-deref?/edx: boolean = false
10070     ba/copy-to-edx 0/imm32/false
10071     # var v: (handle var)
10072     68/push 0/imm32
10073     68/push 0/imm32
10074     89/<- %ebx 4/r32/esp
10075     #
10076     (allocate Heap *Stmt-size *(ebp+0x14))
10077     # var out-addr/edi: (addr stmt) = lookup(*out)
10078     8b/-> *(ebp+0x14) 7/r32/edi
10079     (lookup *edi *(edi+4))  # => eax
10080     89/<- %edi 0/r32/eax
10081     # out-addr->tag = 1/stmt
10082     c7 0/subop/copy *edi 1/imm32/stmt1  # Stmt-tag
10083     {
10084       (stmt-has-outputs? *(ebp+8))
10085       3d/compare-eax-and 0/imm32/false
10086       0f 84/jump-if-= break/disp32
10087       {
10088 $parse-mu-stmt:read-outputs:
10089         # name = next-mu-token(line)
10090         (next-mu-token *(ebp+8) %ecx)
10091         # if slice-empty?(word-slice) break
10092         (slice-empty? %ecx)  # => eax
10093         3d/compare-eax-and 0/imm32/false
10094         0f 85/jump-if-!= break/disp32
10095         # if (name == "<-") break
10096         (slice-equal? %ecx "<-")  # => eax
10097         3d/compare-eax-and 0/imm32/false
10098         0f 85/jump-if-!= break/disp32
10099         # is-deref? = false
10100         ba/copy-to-edx 0/imm32/false
10101         # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
10102         8b/-> *ecx 0/r32/eax  # Slice-start
10103         8a/copy-byte *eax 0/r32/AL
10104         81 4/subop/and %eax 0xff/imm32
10105         3d/compare-eax-and 0x2a/imm32/asterisk
10106         {
10107           75/jump-if-!= break/disp8
10108           ff 0/subop/increment *ecx
10109           ba/copy-to-edx 1/imm32/true
10110         }
10111         # assert(is-identifier?(name))
10112         (is-identifier? %ecx)  # => eax
10113         3d/compare-eax-and 0/imm32/false
10114         0f 84/jump-if-= $parse-mu-stmt:abort/disp32
10115         #
10116         (lookup-var-or-find-in-fn-outputs %ecx *(ebp+0xc) *(ebp+0x10) %ebx *(ebp+0x18) *(ebp+0x1c))
10117         8d/copy-address *(edi+0x14) 0/r32/eax  # Stmt1-outputs
10118         (append-stmt-var Heap  *ebx *(ebx+4)  *(edi+0x14) *(edi+0x18)  %edx  %eax)  # Stmt1-outputs
10119         #
10120         e9/jump loop/disp32
10121       }
10122     }
10123     (add-operation-and-inputs-to-stmt %edi *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
10124 $parse-mu-stmt:define-outputs:
10125     # var output/edi: (addr stmt-var) = lookup(out-addr->outputs)
10126     (lookup *(edi+0x14) *(edi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
10127     89/<- %edi 0/r32/eax
10128     {
10129 $parse-mu-stmt:define-outputs-loop:
10130       # if (output == null) break
10131       81 7/subop/compare %edi 0/imm32
10132       74/jump-if-= break/disp8
10133       #
10134       (maybe-define-var *edi *(edi+4)  *(ebp+0xc))  # if output is a deref, then it's already been defined,
10135                                                     # and must be in vars. This call will be a no-op, but safe.
10136       # output = output->next
10137       (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
10138       89/<- %edi 0/r32/eax
10139       #
10140       eb/jump loop/disp8
10141     }
10142 $parse-mu-stmt:end:
10143     # . reclaim locals
10144     81 0/subop/add %esp 0x10/imm32
10145     # . restore registers
10146     5f/pop-to-edi
10147     5b/pop-to-ebx
10148     5a/pop-to-edx
10149     59/pop-to-ecx
10150     58/pop-to-eax
10151     # . epilogue
10152     89/<- %esp 5/r32/ebp
10153     5d/pop-to-ebp
10154     c3/return
10155 
10156 $parse-mu-stmt:abort:
10157     # error("invalid identifier '" name "'\n")
10158     (write-buffered *(ebp+0x18) "invalid identifier '")
10159     (write-slice-buffered *(ebp+0x18) %ecx)
10160     (write-buffered *(ebp+0x18) "'\n")
10161     (flush *(ebp+0x18))
10162     (stop *(ebp+0x1c) 1)
10163     # never gets here
10164 
10165 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)
10166     # pseudocode:
10167     #   stmt->name = slice-to-string(next-mu-token(line))
10168     #   while true
10169     #     name = next-mu-token(line)
10170     #     v = lookup-var-or-literal(name)
10171     #     stmt->inouts = append(v, stmt->inouts)
10172     #
10173     # . prologue
10174     55/push-ebp
10175     89/<- %ebp 4/r32/esp
10176     # . save registers
10177     50/push-eax
10178     51/push-ecx
10179     52/push-edx
10180     53/push-ebx
10181     56/push-esi
10182     57/push-edi
10183     # edi = stmt
10184     8b/-> *(ebp+8) 7/r32/edi
10185     # var name/ecx: slice
10186     68/push 0/imm32/end
10187     68/push 0/imm32/start
10188     89/<- %ecx 4/r32/esp
10189     # var is-deref?/edx: boolean = false
10190     ba/copy-to-edx 0/imm32/false
10191     # var v/esi: (handle var)
10192     68/push 0/imm32
10193     68/push 0/imm32
10194     89/<- %esi 4/r32/esp
10195 $add-operation-and-inputs-to-stmt:read-operation:
10196     (next-mu-token *(ebp+0xc) %ecx)
10197     8d/copy-address *(edi+4) 0/r32/eax  # Stmt1-operation or Regvardef-operationStmt1-operation or Regvardef-operation
10198     (slice-to-string Heap %ecx %eax)
10199     # var is-get?/ebx: boolean = (name == "get")
10200     (slice-equal? %ecx "get")  # => eax
10201     89/<- %ebx 0/r32/eax
10202     {
10203 $add-operation-and-inputs-to-stmt:read-inouts:
10204       # name = next-mu-token(line)
10205       (next-mu-token *(ebp+0xc) %ecx)
10206       # if slice-empty?(word-slice) break
10207       (slice-empty? %ecx)  # => eax
10208       3d/compare-eax-and 0/imm32/false
10209       0f 85/jump-if-!= break/disp32
10210       # if (name == "<-") abort
10211       (slice-equal? %ecx "<-")
10212       3d/compare-eax-and 0/imm32/false
10213       0f 85/jump-if-!= $add-operation-and-inputs-to-stmt:abort/disp32
10214       # if (is-get? && second operand) lookup or create offset
10215       {
10216         81 7/subop/compare %ebx 0/imm32/false
10217         74/jump-if-= break/disp8
10218         (lookup *(edi+0xc) *(edi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
10219         3d/compare-eax-and 0/imm32
10220         74/jump-if-= break/disp8
10221         (lookup-or-create-constant %eax %ecx %esi)
10222 #?         (lookup *esi *(esi+4))
10223 #?         (write-buffered Stderr "creating new output var ")
10224 #?         (write-int32-hex-buffered Stderr %eax)
10225 #?         (write-buffered Stderr " for field called ")
10226 #?         (write-slice-buffered Stderr %ecx)
10227 #?         (write-buffered Stderr "; var name ")
10228 #?         (lookup *eax *(eax+4))  # Var-name
10229 #?         (write-buffered Stderr %eax)
10230 #?         (write-buffered Stderr Newline)
10231 #?         (flush Stderr)
10232         e9/jump $add-operation-and-inputs-to-stmt:save-var/disp32
10233       }
10234       # is-deref? = false
10235       ba/copy-to-edx 0/imm32/false
10236       # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
10237       8b/-> *ecx 0/r32/eax  # Slice-start
10238       8a/copy-byte *eax 0/r32/AL
10239       81 4/subop/and %eax 0xff/imm32
10240       3d/compare-eax-and 0x2a/imm32/asterisk
10241       {
10242         75/jump-if-!= break/disp8
10243 $add-operation-and-inputs-to-stmt:inout-is-deref:
10244         ff 0/subop/increment *ecx
10245         ba/copy-to-edx 1/imm32/true
10246       }
10247       (lookup-var-or-literal %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
10248 $add-operation-and-inputs-to-stmt:save-var:
10249       8d/copy-address *(edi+0xc) 0/r32/eax
10250       (append-stmt-var Heap  *esi *(esi+4)  *(edi+0xc) *(edi+0x10)  %edx  %eax)  # Stmt1-inouts or Regvardef-inouts
10251       #
10252       e9/jump loop/disp32
10253     }
10254 $add-operation-and-inputs-to-stmt:end:
10255     # . reclaim locals
10256     81 0/subop/add %esp 0x10/imm32
10257     # . restore registers
10258     5f/pop-to-edi
10259     5e/pop-to-esi
10260     5b/pop-to-ebx
10261     5a/pop-to-edx
10262     59/pop-to-ecx
10263     58/pop-to-eax
10264     # . epilogue
10265     89/<- %esp 5/r32/ebp
10266     5d/pop-to-ebp
10267     c3/return
10268 
10269 $add-operation-and-inputs-to-stmt:abort:
10270     # error("fn ___: invalid identifier in '" line "'\n")
10271     (write-buffered *(ebp+0x18) "fn ")
10272     8b/-> *(ebp+0x14) 0/r32/eax
10273     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10274     (write-buffered *(ebp+0x18) %eax)
10275     (rewind-stream *(ebp+0xc))
10276     (write-buffered *(ebp+0x18) ": invalid identifier in '")
10277     (write-stream-data *(ebp+0x18) *(ebp+0xc))
10278     (write-buffered *(ebp+0x18) "'\n")
10279     (flush *(ebp+0x18))
10280     (stop *(ebp+0x1c) 1)
10281     # never gets here
10282 
10283 stmt-has-outputs?:  # line: (addr stream byte) -> result/eax: boolean
10284     # . prologue
10285     55/push-ebp
10286     89/<- %ebp 4/r32/esp
10287     # . save registers
10288     51/push-ecx
10289     # var word-slice/ecx: slice
10290     68/push 0/imm32/end
10291     68/push 0/imm32/start
10292     89/<- %ecx 4/r32/esp
10293     # result = false
10294     b8/copy-to-eax 0/imm32/false
10295     (rewind-stream *(ebp+8))
10296     {
10297       (next-mu-token *(ebp+8) %ecx)
10298       # if slice-empty?(word-slice) break
10299       (slice-empty? %ecx)
10300       3d/compare-eax-and 0/imm32/false
10301       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
10302       0f 85/jump-if-!= break/disp32
10303       # if slice-starts-with?(word-slice, '#') break
10304       # . eax = *word-slice->start
10305       8b/-> *ecx 0/r32/eax
10306       8a/copy-byte *eax 0/r32/AL
10307       81 4/subop/and %eax 0xff/imm32
10308       # . if (eax == '#') break
10309       3d/compare-eax-and 0x23/imm32/hash
10310       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
10311       0f 84/jump-if-= break/disp32
10312       # if slice-equal?(word-slice, '<-') return true
10313       (slice-equal? %ecx "<-")
10314       3d/compare-eax-and 0/imm32/false
10315       74/jump-if-= loop/disp8
10316       b8/copy-to-eax 1/imm32/true
10317     }
10318 $stmt-has-outputs:end:
10319     (rewind-stream *(ebp+8))
10320     # . reclaim locals
10321     81 0/subop/add %esp 8/imm32
10322     # . restore registers
10323     59/pop-to-ecx
10324     # . epilogue
10325     89/<- %esp 5/r32/ebp
10326     5d/pop-to-ebp
10327     c3/return
10328 
10329 # if 'name' starts with a digit, create a new literal var for it
10330 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found
10331 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)
10332     # . prologue
10333     55/push-ebp
10334     89/<- %ebp 4/r32/esp
10335     # . save registers
10336     50/push-eax
10337     51/push-ecx
10338     56/push-esi
10339     # esi = name
10340     8b/-> *(ebp+8) 6/r32/esi
10341     # if slice-empty?(name) abort
10342     (slice-empty? %esi)  # => eax
10343     3d/compare-eax-and 0/imm32/false
10344     0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32
10345     # var c/ecx: byte = *name->start
10346     8b/-> *esi 1/r32/ecx
10347     8a/copy-byte *ecx 1/r32/CL
10348     81 4/subop/and %ecx 0xff/imm32
10349     # if is-decimal-digit?(c) return new var(name)
10350     {
10351       (is-decimal-digit? %ecx)  # => eax
10352       3d/compare-eax-and 0/imm32/false
10353       74/jump-if-= break/disp8
10354 $lookup-var-or-literal:literal:
10355       (new-literal-integer Heap %esi *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
10356       eb/jump $lookup-var-or-literal:end/disp8
10357     }
10358     # else if (c == '"') return new var(name)
10359     {
10360       81 7/subop/compare %ecx 0x22/imm32/dquote
10361       75/jump-if-!= break/disp8
10362 $lookup-var-or-literal:literal-string:
10363       (new-literal Heap %esi *(ebp+0x10))
10364       eb/jump $lookup-var-or-literal:end/disp8
10365     }
10366     # otherwise return lookup-var(name, vars)
10367     {
10368 $lookup-var-or-literal:var:
10369       (lookup-var %esi *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
10370     }
10371 $lookup-var-or-literal:end:
10372     # . restore registers
10373     5e/pop-to-esi
10374     59/pop-to-ecx
10375     58/pop-to-eax
10376     # . epilogue
10377     89/<- %esp 5/r32/ebp
10378     5d/pop-to-ebp
10379     c3/return
10380 
10381 $lookup-var-or-literal:abort:
10382     (write-buffered *(ebp+0x18) "fn ")
10383     8b/-> *(ebp+0x14) 0/r32/eax
10384     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10385     (write-buffered *(ebp+0x18) %eax)
10386     (write-buffered *(ebp+0x18) ": empty variable!")
10387     (flush *(ebp+0x18))
10388     (stop *(ebp+0x1c) 1)
10389     # never gets here
10390 
10391 # return first 'name' from the top (back) of 'vars' and abort if not found
10392 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)
10393     # . prologue
10394     55/push-ebp
10395     89/<- %ebp 4/r32/esp
10396     # . save registers
10397     50/push-eax
10398     #
10399     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
10400     # if (*out == 0) abort
10401     8b/-> *(ebp+0x10) 0/r32/eax
10402     81 7/subop/compare *eax 0/imm32
10403     74/jump-if-= $lookup-var:abort/disp8
10404 $lookup-var:end:
10405     # . restore registers
10406     58/pop-to-eax
10407     # . epilogue
10408     89/<- %esp 5/r32/ebp
10409     5d/pop-to-ebp
10410     c3/return
10411 
10412 $lookup-var:abort:
10413     (write-buffered *(ebp+0x18) "fn ")
10414     8b/-> *(ebp+0x14) 0/r32/eax
10415     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10416     (write-buffered *(ebp+0x18) %eax)
10417     (write-buffered *(ebp+0x18) ": unknown variable '")
10418     (write-slice-buffered *(ebp+0x18) *(ebp+8))
10419     (write-buffered *(ebp+0x18) "'\n")
10420     (flush *(ebp+0x18))
10421     (stop *(ebp+0x1c) 1)
10422     # never gets here
10423 
10424 # return first 'name' from the top (back) of 'vars', and 0/null if not found
10425 # ensure that 'name' if in a register is the topmost variable in that register
10426 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)
10427     # pseudocode:
10428     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
10429     #   var min = vars->data
10430     #   while curr >= min
10431     #     var v: (handle var) = *curr
10432     #     if v->name == name
10433     #       return
10434     #     curr -= 12
10435     #
10436     # . prologue
10437     55/push-ebp
10438     89/<- %ebp 4/r32/esp
10439     # . save registers
10440     50/push-eax
10441     51/push-ecx
10442     52/push-edx
10443     53/push-ebx
10444     56/push-esi
10445     57/push-edi
10446     # clear out
10447     (zero-out *(ebp+0x10) *Handle-size)
10448     # esi = vars
10449     8b/-> *(ebp+0xc) 6/r32/esi
10450     # ebx = vars->top
10451     8b/-> *esi 3/r32/ebx
10452     # if (vars->top > vars->size) abort
10453     3b/compare<- *(esi+4) 0/r32/eax
10454     0f 8f/jump-if-> $lookup-var-helper:error1/disp32
10455     # var min/edx: (addr handle var) = vars->data
10456     8d/copy-address *(esi+8) 2/r32/edx
10457     # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
10458     8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
10459     # var var-in-reg/edi: 8 addrs
10460     68/push 0/imm32
10461     68/push 0/imm32
10462     68/push 0/imm32
10463     68/push 0/imm32
10464     68/push 0/imm32
10465     68/push 0/imm32
10466     68/push 0/imm32
10467     68/push 0/imm32
10468     89/<- %edi 4/r32/esp
10469     {
10470 $lookup-var-helper:loop:
10471       # if (curr < min) return
10472       39/compare %ebx 2/r32/edx
10473       0f 82/jump-if-addr< break/disp32
10474       # var v/ecx: (addr var) = lookup(*curr)
10475       (lookup *ebx *(ebx+4))  # => eax
10476       89/<- %ecx 0/r32/eax
10477       # var vn/eax: (addr array byte) = lookup(v->name)
10478       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
10479       # if (vn == name) return curr
10480       (slice-equal? *(ebp+8) %eax)  # => eax
10481       3d/compare-eax-and 0/imm32/false
10482       {
10483         74/jump-if-= break/disp8
10484 $lookup-var-helper:found:
10485         # var vr/eax: (addr array byte) = lookup(v->register)
10486         (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
10487         3d/compare-eax-and 0/imm32
10488         {
10489           74/jump-if-= break/disp8
10490 $lookup-var-helper:found-register:
10491           # var reg/eax: int = get(Registers, vr)
10492           (get Mu-registers %eax 0xc "Mu-registers")  # => eax
10493           8b/-> *eax 0/r32/eax
10494           # if (var-in-reg[reg]) error
10495           8b/-> *(edi+eax<<2) 0/r32/eax
10496           3d/compare-eax-and 0/imm32
10497           0f 85/jump-if-!= $lookup-var-helper:error2/disp32
10498         }
10499 $lookup-var-helper:return:
10500         # esi = out
10501         8b/-> *(ebp+0x10) 6/r32/esi
10502         # *out = *curr
10503         8b/-> *ebx 0/r32/eax
10504         89/<- *esi 0/r32/eax
10505         8b/-> *(ebx+4) 0/r32/eax
10506         89/<- *(esi+4) 0/r32/eax
10507         # return
10508         eb/jump $lookup-var-helper:end/disp8
10509       }
10510       # 'name' not yet found; update var-in-reg if v in register
10511       # . var vr/eax: (addr array byte) = lookup(v->register)
10512       (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
10513       # . if (var == 0) continue
10514       3d/compare-eax-and 0/imm32
10515       74/jump-if-= $lookup-var-helper:continue/disp8
10516       # . var reg/eax: int = get(Registers, vr)
10517       (get Mu-registers %eax 0xc "Mu-registers")  # => eax
10518       8b/-> *eax 0/r32/eax
10519       # . if (var-in-reg[reg] == 0) var-in-reg[reg] = v
10520       81 7/subop/compare *(edi+eax<<2) 0/imm32
10521       75/jump-if-!= $lookup-var-helper:continue/disp8
10522       89/<- *(edi+eax<<2) 1/r32/ecx
10523 $lookup-var-helper:continue:
10524       # curr -= 12
10525       81 5/subop/subtract %ebx 0xc/imm32
10526       e9/jump loop/disp32
10527     }
10528 $lookup-var-helper:end:
10529     # . reclaim locals
10530     81 0/subop/add %esp 0x20/imm32
10531     # . restore registers
10532     5f/pop-to-edi
10533     5e/pop-to-esi
10534     5b/pop-to-ebx
10535     5a/pop-to-edx
10536     59/pop-to-ecx
10537     58/pop-to-eax
10538     # . epilogue
10539     89/<- %esp 5/r32/ebp
10540     5d/pop-to-ebp
10541     c3/return
10542 
10543 $lookup-var-helper:error1:
10544     (write-buffered *(ebp+0x18) "fn ")
10545     8b/-> *(ebp+0x14) 0/r32/eax
10546     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10547     (write-buffered *(ebp+0x18) %eax)
10548     (write-buffered *(ebp+0x18) ": malformed stack when looking up '")
10549     (write-slice-buffered *(ebp+0x18) *(ebp+8))
10550     (write-buffered *(ebp+0x18) "'\n")
10551     (flush *(ebp+0x18))
10552     (stop *(ebp+0x1c) 1)
10553     # never gets here
10554 
10555 $lookup-var-helper:error2:
10556     # eax contains the conflicting var at this point
10557     (write-buffered *(ebp+0x18) "fn ")
10558     50/push-eax
10559     8b/-> *(ebp+0x14) 0/r32/eax
10560     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10561     (write-buffered *(ebp+0x18) %eax)
10562     58/pop-eax
10563     (write-buffered *(ebp+0x18) ": register ")
10564     50/push-eax
10565     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
10566     (write-buffered *(ebp+0x18) %eax)
10567     58/pop-to-eax
10568     (write-buffered *(ebp+0x18) " reads var '")
10569     (write-slice-buffered *(ebp+0x18) *(ebp+8))
10570     (write-buffered *(ebp+0x18) "' after writing var '")
10571     (lookup *eax *(eax+4))  # Var-name Var-name => eax
10572     (write-buffered *(ebp+0x18) %eax)
10573     (write-buffered *(ebp+0x18) "'\n")
10574     (flush *(ebp+0x18))
10575     (stop *(ebp+0x1c) 1)
10576     # never gets here
10577 
10578 dump-vars:  # vars: (addr stack live-var)
10579     # pseudocode:
10580     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
10581     #   var min = vars->data
10582     #   while curr >= min
10583     #     var v: (handle var) = *curr
10584     #     print v
10585     #     curr -= 12
10586     #
10587     # . prologue
10588     55/push-ebp
10589     89/<- %ebp 4/r32/esp
10590     # . save registers
10591     52/push-edx
10592     53/push-ebx
10593     56/push-esi
10594     # esi = vars
10595     8b/-> *(ebp+8) 6/r32/esi
10596     # ebx = vars->top
10597     8b/-> *esi 3/r32/ebx
10598     # var min/edx: (addr handle var) = vars->data
10599     8d/copy-address *(esi+8) 2/r32/edx
10600     # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
10601     8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
10602     {
10603 $dump-vars:loop:
10604       # if (curr < min) return
10605       39/compare %ebx 2/r32/edx
10606       0f 82/jump-if-addr< break/disp32
10607       #
10608       (write-buffered Stderr "  var@")
10609       (dump-var 2 %ebx)
10610       # curr -= 12
10611       81 5/subop/subtract %ebx 0xc/imm32
10612       e9/jump loop/disp32
10613     }
10614 $dump-vars:end:
10615     # . restore registers
10616     5e/pop-to-esi
10617     5b/pop-to-ebx
10618     5a/pop-to-edx
10619     # . epilogue
10620     89/<- %esp 5/r32/ebp
10621     5d/pop-to-ebp
10622     c3/return
10623 
10624 == data
10625 # Like Registers, but no esp or ebp
10626 Mu-registers:  # (addr stream {(handle array byte), int})
10627   # a table is a stream
10628   0x48/imm32/write
10629   0/imm32/read
10630   0x48/imm32/length
10631   # data
10632   # it is perfectly ok to use fake alloc-ids -- as long as you never try to reclaim them
10633   0x11/imm32/alloc-id $Mu-register-eax/imm32 0/imm32
10634   0x11/imm32/alloc-id $Mu-register-ecx/imm32 1/imm32
10635   0x11/imm32/alloc-id $Mu-register-edx/imm32 2/imm32
10636   0x11/imm32/alloc-id $Mu-register-ebx/imm32 3/imm32
10637   0x11/imm32/alloc-id $Mu-register-esi/imm32 6/imm32
10638   0x11/imm32/alloc-id $Mu-register-edi/imm32 7/imm32
10639 
10640 $Mu-register-eax:
10641   0x11/imm32/alloc-id
10642   3/imm32/size
10643   0x65/e 0x61/a 0x78/x
10644 
10645 $Mu-register-ecx:
10646   0x11/imm32/alloc-id
10647   3/imm32/size
10648   0x65/e 0x63/c 0x78/x
10649 
10650 $Mu-register-edx:
10651   0x11/imm32/alloc-id
10652   3/imm32/size
10653   0x65/e 0x64/d 0x78/x
10654 
10655 $Mu-register-ebx:
10656   0x11/imm32/alloc-id
10657   3/imm32/size
10658   0x65/e 0x62/b 0x78/x
10659 
10660 $Mu-register-esi:
10661   0x11/imm32/alloc-id
10662   3/imm32/size
10663   0x65/e 0x73/s 0x69/i
10664 
10665 $Mu-register-edi:
10666   0x11/imm32/alloc-id
10667   3/imm32/size
10668   0x65/e 0x64/d 0x69/i
10669 
10670 == code
10671 
10672 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found
10673 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)
10674     # . prologue
10675     55/push-ebp
10676     89/<- %ebp 4/r32/esp
10677     # . save registers
10678     50/push-eax
10679     #
10680     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))  # arg order slightly different; 'fn' is deemphasized
10681     {
10682       # if (out != 0) return
10683       8b/-> *(ebp+0x14) 0/r32/eax
10684       81 7/subop/compare *eax 0/imm32
10685       75/jump-if-!= break/disp8
10686       # if name is one of fn's outputs, return it
10687       (find-in-function-outputs *(ebp+0x10) *(ebp+8) *(ebp+0x14))
10688       8b/-> *(ebp+0x14) 0/r32/eax
10689       81 7/subop/compare *eax 0/imm32
10690       # otherwise abort
10691       0f 84/jump-if-= $lookup-or-define-var:abort/disp32
10692     }
10693 $lookup-or-define-var:end:
10694     # . restore registers
10695     58/pop-to-eax
10696     # . epilogue
10697     89/<- %esp 5/r32/ebp
10698     5d/pop-to-ebp
10699     c3/return
10700 
10701 $lookup-or-define-var:abort:
10702     (write-buffered *(ebp+0x18) "unknown variable '")
10703     (write-slice-buffered *(ebp+0x18) *(ebp+8))
10704     (write-buffered *(ebp+0x18) "'\n")
10705     (flush *(ebp+0x18))
10706     (stop *(ebp+0x1c) 1)
10707     # never gets here
10708 
10709 find-in-function-outputs:  # fn: (addr function), name: (addr slice), out: (addr handle var)
10710     # . prologue
10711     55/push-ebp
10712     89/<- %ebp 4/r32/esp
10713     # . save registers
10714     50/push-eax
10715     51/push-ecx
10716     # var curr/ecx: (addr list var) = lookup(fn->outputs)
10717     8b/-> *(ebp+8) 1/r32/ecx
10718     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
10719     89/<- %ecx 0/r32/eax
10720     # while curr != null
10721     {
10722       81 7/subop/compare %ecx 0/imm32
10723       74/jump-if-= break/disp8
10724       # var v/eax: (addr var) = lookup(curr->value)
10725       (lookup *ecx *(ecx+4))  # List-value List-value => eax
10726       # var s/eax: (addr array byte) = lookup(v->name)
10727       (lookup *eax *(eax+4))  # Var-name Var-name => eax
10728       # if (s == name) return curr->value
10729       (slice-equal? *(ebp+0xc) %eax)  # => eax
10730       3d/compare-eax-and 0/imm32/false
10731       {
10732         74/jump-if-= break/disp8
10733         # var edi = out
10734         57/push-edi
10735         8b/-> *(ebp+0x10) 7/r32/edi
10736         # *out = curr->value
10737         8b/-> *ecx 0/r32/eax
10738         89/<- *edi 0/r32/eax
10739         8b/-> *(ecx+4) 0/r32/eax
10740         89/<- *(edi+4) 0/r32/eax
10741         #
10742         5f/pop-to-edi
10743         eb/jump $find-in-function-outputs:end/disp8
10744       }
10745       # curr = curr->next
10746       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
10747       89/<- %ecx 0/r32/eax
10748       #
10749       eb/jump loop/disp8
10750     }
10751     b8/copy-to-eax 0/imm32
10752 $find-in-function-outputs:end:
10753     # . restore registers
10754     59/pop-to-ecx
10755     58/pop-to-eax
10756     # . epilogue
10757     89/<- %esp 5/r32/ebp
10758     5d/pop-to-ebp
10759     c3/return
10760 
10761 # push 'out' to 'vars' if not already there; it's assumed to be a fn output
10762 maybe-define-var:  # out: (handle var), vars: (addr stack live-var)
10763     # . prologue
10764     55/push-ebp
10765     89/<- %ebp 4/r32/esp
10766     # . save registers
10767     50/push-eax
10768     # var out-addr/eax: (addr var)
10769     (lookup *(ebp+8) *(ebp+0xc))  # => eax
10770     #
10771     (binding-exists? %eax *(ebp+0x10))  # => eax
10772     3d/compare-eax-and 0/imm32/false
10773     75/jump-if-!= $maybe-define-var:end/disp8
10774     # otherwise update vars
10775     (push *(ebp+0x10) *(ebp+8))
10776     (push *(ebp+0x10) *(ebp+0xc))
10777     (push *(ebp+0x10) 0)  # 'out' is always a fn output; never spill it
10778 $maybe-define-var:end:
10779     # . restore registers
10780     58/pop-to-eax
10781     # . epilogue
10782     89/<- %esp 5/r32/ebp
10783     5d/pop-to-ebp
10784     c3/return
10785 
10786 # simpler version of lookup-var-helper
10787 binding-exists?:  # target: (addr var), vars: (addr stack live-var) -> result/eax: boolean
10788     # pseudocode:
10789     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
10790     #   var min = vars->data
10791     #   while curr >= min
10792     #     var v: (handle var) = *curr
10793     #     if v->name == target->name
10794     #       return true
10795     #     curr -= 12
10796     #   return false
10797     #
10798     # . prologue
10799     55/push-ebp
10800     89/<- %ebp 4/r32/esp
10801     # . save registers
10802     51/push-ecx
10803     52/push-edx
10804     56/push-esi
10805     # var target-name/ecx: (addr array byte) = lookup(target->name)
10806     8b/-> *(ebp+8) 0/r32/eax
10807     (lookup *eax *(eax+4))  # Var-name Var-name => eax
10808     89/<- %ecx 0/r32/eax
10809     # esi = vars
10810     8b/-> *(ebp+0xc) 6/r32/esi
10811     # eax = vars->top
10812     8b/-> *esi 0/r32/eax
10813     # var min/edx: (addr handle var) = vars->data
10814     8d/copy-address *(esi+8) 2/r32/edx
10815     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
10816     8d/copy-address *(esi+eax-4) 6/r32/esi  # vars + 8 + vars->type - 12
10817     {
10818 $binding-exists?:loop:
10819       # if (curr < min) return
10820       39/compare %esi 2/r32/edx
10821       0f 82/jump-if-addr< break/disp32
10822       # var v/eax: (addr var) = lookup(*curr)
10823       (lookup *esi *(esi+4))  # => eax
10824       # var vn/eax: (addr array byte) = lookup(v->name)
10825       (lookup *eax *(eax+4))  # Var-name Var-name => eax
10826       # if (vn == target-name) return true
10827       (string-equal? %ecx %eax)  # => eax
10828       3d/compare-eax-and 0/imm32/false
10829       75/jump-if-!= $binding-exists?:end/disp8  # eax already contains true
10830       # curr -= 12
10831       81 5/subop/subtract %esi 0xc/imm32
10832       e9/jump loop/disp32
10833     }
10834     b8/copy-to-eax 0/imm32/false
10835 $binding-exists?:end:
10836     # . restore registers
10837     5e/pop-to-esi
10838     5a/pop-to-edx
10839     59/pop-to-ecx
10840     # . epilogue
10841     89/<- %esp 5/r32/ebp
10842     5d/pop-to-ebp
10843     c3/return
10844 
10845 test-parse-mu-stmt:
10846     # . prologue
10847     55/push-ebp
10848     89/<- %ebp 4/r32/esp
10849     # setup
10850     (clear-stream _test-input-stream)
10851     (write _test-input-stream "increment n\n")
10852     # var vars/ecx: (stack (addr var) 16)
10853     81 5/subop/subtract %esp 0xc0/imm32
10854     68/push 0xc0/imm32/size
10855     68/push 0/imm32/top
10856     89/<- %ecx 4/r32/esp
10857     (clear-stack %ecx)
10858     # var v/edx: (handle var)
10859     68/push 0/imm32
10860     68/push 0/imm32
10861     89/<- %edx 4/r32/esp
10862     # var s/eax: (handle array byte)
10863     68/push 0/imm32
10864     68/push 0/imm32
10865     89/<- %eax 4/r32/esp
10866     # v = new var("n")
10867     (copy-array Heap "n" %eax)
10868     (new-var Heap *eax *(eax+4) %edx)
10869     #
10870     (push %ecx *edx)
10871     (push %ecx *(edx+4))
10872     (push %ecx 0)
10873     # var out/eax: (handle stmt)
10874     68/push 0/imm32
10875     68/push 0/imm32
10876     89/<- %eax 4/r32/esp
10877     # convert
10878     (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
10879     # var out-addr/edx: (addr stmt) = lookup(*out)
10880     (lookup *eax *(eax+4))  # => eax
10881     89/<- %edx 0/r32/eax
10882     # out->tag
10883     (check-ints-equal *edx 1 "F - test-parse-mu-stmt/tag")  # Stmt-tag is Stmt1
10884     # out->operation
10885     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
10886     (check-strings-equal %eax "increment" "F - test-parse-mu-stmt/name")  # Stmt1-operation
10887     # out->inouts->value->name
10888     # . eax = out->inouts
10889     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
10890     # . eax = out->inouts->value
10891     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10892     # . eax = out->inouts->value->name
10893     (lookup *eax *(eax+4))  # Var-name Var-name => eax
10894     # .
10895     (check-strings-equal %eax "n" "F - test-parse-mu-stmt/inout:0")
10896     # . epilogue
10897     89/<- %esp 5/r32/ebp
10898     5d/pop-to-ebp
10899     c3/return
10900 
10901 test-parse-mu-stmt-with-comma:
10902     # . prologue
10903     55/push-ebp
10904     89/<- %ebp 4/r32/esp
10905     # setup
10906     (clear-stream _test-input-stream)
10907     (write _test-input-stream "copy-to n, 3\n")
10908     # var vars/ecx: (stack (addr var) 16)
10909     81 5/subop/subtract %esp 0xc0/imm32
10910     68/push 0xc0/imm32/size
10911     68/push 0/imm32/top
10912     89/<- %ecx 4/r32/esp
10913     (clear-stack %ecx)
10914     # var v/edx: (handle var)
10915     68/push 0/imm32
10916     68/push 0/imm32
10917     89/<- %edx 4/r32/esp
10918     # var s/eax: (handle array byte)
10919     68/push 0/imm32
10920     68/push 0/imm32
10921     89/<- %eax 4/r32/esp
10922     # v = new var("n")
10923     (copy-array Heap "n" %eax)
10924     (new-var Heap *eax *(eax+4) %edx)
10925     #
10926     (push %ecx *edx)
10927     (push %ecx *(edx+4))
10928     (push %ecx 0)
10929     # var out/eax: (handle stmt)
10930     68/push 0/imm32
10931     68/push 0/imm32
10932     89/<- %eax 4/r32/esp
10933     # convert
10934     (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
10935     # var out-addr/edx: (addr stmt) = lookup(*out)
10936     (lookup *eax *(eax+4))  # => eax
10937     89/<- %edx 0/r32/eax
10938     # out->tag
10939     (check-ints-equal *edx 1 "F - test-parse-mu-stmt-with-comma/tag")  # Stmt-tag is Stmt1
10940     # out->operation
10941     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
10942     (check-strings-equal %eax "copy-to" "F - test-parse-mu-stmt-with-comma/name")  # Stmt1-operation
10943     # out->inouts->value->name
10944     # . eax = out->inouts
10945     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
10946     # . eax = out->inouts->value
10947     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10948     # . eax = out->inouts->value->name
10949     (lookup *eax *(eax+4))  # Var-name Var-name => eax
10950     # .
10951     (check-strings-equal %eax "n" "F - test-parse-mu-stmt-with-comma/inout:0")
10952     # . epilogue
10953     89/<- %esp 5/r32/ebp
10954     5d/pop-to-ebp
10955     c3/return
10956 
10957 new-var:  # ad: (addr allocation-descriptor), name: (handle array byte), out: (addr handle var)
10958     # . prologue
10959     55/push-ebp
10960     89/<- %ebp 4/r32/esp
10961     # . save registers
10962     50/push-eax
10963     51/push-ecx
10964     # ecx = out
10965     8b/-> *(ebp+0x14) 1/r32/ecx
10966     #
10967     (allocate *(ebp+8) *Var-size %ecx)
10968     # var out-addr/eax: (addr var)
10969     (lookup *ecx *(ecx+4))  # => eax
10970     # out-addr->name = name
10971     8b/-> *(ebp+0xc) 1/r32/ecx
10972     89/<- *eax 1/r32/ecx  # Var-name
10973     8b/-> *(ebp+0x10) 1/r32/ecx
10974     89/<- *(eax+4) 1/r32/ecx  # Var-name
10975 #?     (write-buffered Stderr "var ")
10976 #?     (lookup *(ebp+0xc) *(ebp+0x10))
10977 #?     (write-buffered Stderr %eax)
10978 #?     (write-buffered Stderr " at ")
10979 #?     8b/-> *(ebp+0x14) 1/r32/ecx
10980 #?     (lookup *ecx *(ecx+4))  # => eax
10981 #?     (write-int32-hex-buffered Stderr %eax)
10982 #?     (write-buffered Stderr Newline)
10983 #?     (flush Stderr)
10984 $new-var:end:
10985     # . restore registers
10986     59/pop-to-ecx
10987     58/pop-to-eax
10988     # . epilogue
10989     89/<- %esp 5/r32/ebp
10990     5d/pop-to-ebp
10991     c3/return
10992 
10993 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)
10994     # . prologue
10995     55/push-ebp
10996     89/<- %ebp 4/r32/esp
10997     # . save registers
10998     50/push-eax
10999     51/push-ecx
11000     # if (!is-hex-int?(name)) abort
11001     (is-hex-int? *(ebp+0xc))  # => eax
11002     3d/compare-eax-and 0/imm32/false
11003     0f 84/jump-if-= $new-literal-integer:abort/disp32
11004     # a little more error-checking
11005     (check-mu-hex-int *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c))
11006     # out = new var(s)
11007     (new-var-from-slice *(ebp+8) *(ebp+0xc) *(ebp+0x10))
11008     # var out-addr/ecx: (addr var) = lookup(*out)
11009     8b/-> *(ebp+0x10) 0/r32/eax
11010     (lookup *eax *(eax+4))  # => eax
11011     89/<- %ecx 0/r32/eax
11012     # out-addr->block-depth = *Curr-block-depth
11013     8b/-> *Curr-block-depth 0/r32/eax
11014     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
11015     # out-addr->type = new tree()
11016     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
11017     (allocate *(ebp+8) *Type-tree-size %eax)
11018     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
11019     c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
11020     # nothing else to do; default type is 'literal'
11021 $new-literal-integer:end:
11022     # . reclaim locals
11023     81 0/subop/add %esp 8/imm32
11024     # . restore registers
11025     59/pop-to-ecx
11026     58/pop-to-eax
11027     # . epilogue
11028     89/<- %esp 5/r32/ebp
11029     5d/pop-to-ebp
11030     c3/return
11031 
11032 $new-literal-integer:abort:
11033     (write-buffered *(ebp+0x18) "fn ")
11034     8b/-> *(ebp+0x14) 0/r32/eax
11035     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11036     (write-buffered *(ebp+0x18) %eax)
11037     (write-buffered *(ebp+0x18) ": variable '")
11038     (write-slice-buffered *(ebp+0x18) *(ebp+0xc))
11039     (write-buffered *(ebp+0x18) "' cannot begin with a digit (or do you have a typo in a number?)\n")
11040     (flush *(ebp+0x18))
11041     (stop *(ebp+0x1c) 1)
11042     # never gets here
11043 
11044 # precondition: name is a valid hex integer; require a '0x' prefix
11045 check-mu-hex-int:  # name: (addr slice), err: (addr buffered-file), ed: (addr exit-descriptor)
11046     # . prologue
11047     55/push-ebp
11048     89/<- %ebp 4/r32/esp
11049     # . save registers
11050     50/push-eax
11051     51/push-ecx
11052     52/push-edx
11053     #
11054     8b/-> *(ebp+8) 1/r32/ecx
11055     # var start/ecx: (addr byte) = name->start
11056     8b/-> *(ecx+4) 2/r32/edx
11057     # var end/ecx: (addr byte) = name->end
11058     8b/-> *ecx 1/r32/ecx
11059     # var len/eax: int = name->end - name->start
11060     89/<- %eax 2/r32/edx
11061     29/subtract-from %eax 1/r32/ecx
11062     # if (len <= 1) return
11063     3d/compare-eax-with 1/imm32
11064     0f 8e/jump-if-<= $check-mu-hex-int:end/disp32
11065 $check-mu-hex-int:length->-1:
11066     # if slice-starts-with?("0x") return
11067     (slice-starts-with? *(ebp+8) "0x")  # => eax
11068     3d/compare-eax-with 0/imm32/false
11069     75/jump-if-!= $check-mu-hex-int:end/disp8
11070 $check-mu-hex-int:abort:
11071     # otherwise abort
11072     (write-buffered *(ebp+0xc) "literal integers are always hex in Mu; either start '")
11073     (write-slice-buffered *(ebp+0xc) *(ebp+8))
11074     (write-buffered *(ebp+0xc) "' with a '0x' to be unambiguous, or convert it to decimal.\n")
11075     (flush *(ebp+0xc))
11076     (stop *(ebp+0x10) 1)
11077 $check-mu-hex-int:end:
11078     # . restore registers
11079     5a/pop-to-edx
11080     59/pop-to-ecx
11081     58/pop-to-eax
11082     # . epilogue
11083     89/<- %esp 5/r32/ebp
11084     5d/pop-to-ebp
11085     c3/return
11086 
11087 new-literal:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
11088     # . prologue
11089     55/push-ebp
11090     89/<- %ebp 4/r32/esp
11091     # . save registers
11092     50/push-eax
11093     51/push-ecx
11094     # var s/ecx: (handle array byte)
11095     68/push 0/imm32
11096     68/push 0/imm32
11097     89/<- %ecx 4/r32/esp
11098     # s = slice-to-string(name)
11099     (slice-to-string Heap *(ebp+0xc) %ecx)
11100     # allocate to out
11101     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
11102     # var out-addr/ecx: (addr var) = lookup(*out)
11103     8b/-> *(ebp+0x10) 1/r32/ecx
11104     (lookup *ecx *(ecx+4))  # => eax
11105     89/<- %ecx 0/r32/eax
11106     # out-addr->block-depth = *Curr-block-depth
11107     8b/-> *Curr-block-depth 0/r32/eax
11108     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
11109     # out-addr->type/eax = new type
11110     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
11111     (allocate *(ebp+8) *Type-tree-size %eax)
11112     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
11113     # nothing else to do; default type is 'literal'
11114     c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
11115 $new-literal:end:
11116     # . reclaim locals
11117     81 0/subop/add %esp 8/imm32
11118     # . restore registers
11119     59/pop-to-ecx
11120     58/pop-to-eax
11121     # . epilogue
11122     89/<- %esp 5/r32/ebp
11123     5d/pop-to-ebp
11124     c3/return
11125 
11126 new-var-from-slice:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
11127     # . prologue
11128     55/push-ebp
11129     89/<- %ebp 4/r32/esp
11130     # . save registers
11131     51/push-ecx
11132     # var tmp/ecx: (handle array byte)
11133     68/push 0/imm32
11134     68/push 0/imm32
11135     89/<- %ecx 4/r32/esp
11136     # tmp = slice-to-string(name)
11137     (slice-to-string Heap *(ebp+0xc) %ecx)
11138     # out = new-var(tmp)
11139     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
11140 $new-var-from-slice:end:
11141     # . reclaim locals
11142     81 0/subop/add %esp 8/imm32
11143     # . restore registers
11144     59/pop-to-ecx
11145     # . epilogue
11146     89/<- %esp 5/r32/ebp
11147     5d/pop-to-ebp
11148     c3/return
11149 
11150 new-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
11151     # . prologue
11152     55/push-ebp
11153     89/<- %ebp 4/r32/esp
11154     # . save registers
11155     50/push-eax
11156     51/push-ecx
11157     #
11158     (allocate *(ebp+8) *Stmt-size *(ebp+0x14))
11159     # var out-addr/eax: (addr stmt) = lookup(*out)
11160     8b/-> *(ebp+0x14) 0/r32/eax
11161     (lookup *eax *(eax+4))  # => eax
11162     # out-addr->tag = stmt
11163     c7 0/subop/copy *eax 2/imm32/tag/var-on-stack  # Stmt-tag
11164     # result->var = var
11165     8b/-> *(ebp+0xc) 1/r32/ecx
11166     89/<- *(eax+4) 1/r32/ecx  # Vardef-var
11167     8b/-> *(ebp+0x10) 1/r32/ecx
11168     89/<- *(eax+8) 1/r32/ecx  # Vardef-var
11169 $new-var-def:end:
11170     # . restore registers
11171     59/pop-to-ecx
11172     58/pop-to-eax
11173     # . epilogue
11174     89/<- %esp 5/r32/ebp
11175     5d/pop-to-ebp
11176     c3/return
11177 
11178 new-reg-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
11179     # . prologue
11180     55/push-ebp
11181     89/<- %ebp 4/r32/esp
11182     # . save registers
11183     50/push-eax
11184     # eax = out
11185     8b/-> *(ebp+0x14) 0/r32/eax
11186     #
11187     (allocate *(ebp+8) *Stmt-size %eax)
11188     # var out-addr/eax: (addr stmt) = lookup(*out)
11189     (lookup *eax *(eax+4))  # => eax
11190     # set tag
11191     c7 0/subop/copy *eax 3/imm32/tag/var-in-register  # Stmt-tag
11192     # set output
11193     8d/copy-address *(eax+0x14) 0/r32/eax  # Regvardef-outputs
11194     (append-stmt-var Heap  *(ebp+0xc) *(ebp+0x10)  0 0  0  %eax)
11195 $new-reg-var-def:end:
11196     # . restore registers
11197     58/pop-to-eax
11198     # . epilogue
11199     89/<- %esp 5/r32/ebp
11200     5d/pop-to-ebp
11201     c3/return
11202 
11203 append-list:  # ad: (addr allocation-descriptor), value: (handle _type), list: (handle list _type), out: (addr handle list _type)
11204     # . prologue
11205     55/push-ebp
11206     89/<- %ebp 4/r32/esp
11207     # . save registers
11208     50/push-eax
11209     51/push-ecx
11210     57/push-edi
11211     # edi = out
11212     8b/-> *(ebp+0x1c) 7/r32/edi
11213     # *out = new list
11214     (allocate *(ebp+8) *List-size %edi)
11215     # var out-addr/edi: (addr list _type) = lookup(*out)
11216     (lookup *edi *(edi+4))  # => eax
11217     89/<- %edi 0/r32/eax
11218     # out-addr->value = value
11219     8b/-> *(ebp+0xc) 0/r32/eax
11220     89/<- *edi 0/r32/eax  # List-value
11221     8b/-> *(ebp+0x10) 0/r32/eax
11222     89/<- *(edi+4) 0/r32/eax  # List-value
11223     # if (list == null) return
11224     81 7/subop/compare *(ebp+0x14) 0/imm32
11225     74/jump-if-= $append-list:end/disp8
11226     # otherwise append
11227 $append-list:non-empty-list:
11228     # var curr/eax: (addr list _type) = lookup(list)
11229     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
11230     # while (curr->next != null) curr = curr->next
11231     {
11232       81 7/subop/compare *(eax+8) 0/imm32  # List-next
11233       74/jump-if-= break/disp8
11234       # curr = lookup(curr->next)
11235       (lookup *(eax+8) *(eax+0xc))  # List-next, List-next => eax
11236       #
11237       eb/jump loop/disp8
11238     }
11239     # edi = out
11240     8b/-> *(ebp+0x1c) 7/r32/edi
11241     # curr->next = out
11242     8b/-> *edi 1/r32/ecx
11243     89/<- *(eax+8) 1/r32/ecx  # List-next
11244     8b/-> *(edi+4) 1/r32/ecx
11245     89/<- *(eax+0xc) 1/r32/ecx  # List-next
11246     # out = list
11247     8b/-> *(ebp+0x14) 1/r32/ecx
11248     89/<- *edi 1/r32/ecx
11249     8b/-> *(ebp+0x18) 1/r32/ecx
11250     89/<- *(edi+4) 1/r32/ecx
11251 $append-list:end:
11252     # . restore registers
11253     5f/pop-to-edi
11254     59/pop-to-ecx
11255     58/pop-to-eax
11256     # . epilogue
11257     89/<- %esp 5/r32/ebp
11258     5d/pop-to-ebp
11259     c3/return
11260 
11261 append-stmt-var:  # ad: (addr allocation-descriptor), v: (handle var), vars: (handle stmt-var), is-deref?: boolean, out: (addr handle stmt-var)
11262     # . prologue
11263     55/push-ebp
11264     89/<- %ebp 4/r32/esp
11265     # . save registers
11266     50/push-eax
11267     51/push-ecx
11268     57/push-edi
11269     # edi = out
11270     8b/-> *(ebp+0x20) 7/r32/edi
11271     # out = new stmt-var
11272     (allocate *(ebp+8) *Stmt-var-size %edi)
11273     # var out-addr/ecx: (addr stmt-var) = lookup(*out)
11274     (lookup *edi *(edi+4))  # => eax
11275     89/<- %ecx 0/r32/eax
11276     # out-addr->value = v
11277     8b/-> *(ebp+0xc) 0/r32/eax
11278     89/<- *ecx 0/r32/eax  # Stmt-var-value
11279     8b/-> *(ebp+0x10) 0/r32/eax
11280     89/<- *(ecx+4) 0/r32/eax  # Stmt-var-value
11281     # out-addr->is-deref? = is-deref?
11282     8b/-> *(ebp+0x1c) 0/r32/eax
11283     89/<- *(ecx+0x10) 0/r32/eax  # Stmt-var-is-deref
11284     # if (vars == null) return result
11285     81 7/subop/compare *(ebp+0x14) 0/imm32/null
11286     74/jump-if-= $append-stmt-var:end/disp8
11287     # otherwise append
11288     # var curr/eax: (addr stmt-var) = lookup(vars)
11289     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
11290     # while (curr->next != null) curr = curr->next
11291     {
11292       81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
11293       74/jump-if-= break/disp8
11294       # curr = lookup(curr->next)
11295       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next, Stmt-var-next => eax
11296       #
11297       eb/jump loop/disp8
11298     }
11299     # curr->next = out
11300     8b/-> *edi 1/r32/ecx
11301     89/<- *(eax+8) 1/r32/ecx  # Stmt-var-next
11302     8b/-> *(edi+4) 1/r32/ecx
11303     89/<- *(eax+0xc) 1/r32/ecx  # Stmt-var-next
11304     # out = vars
11305     8b/-> *(ebp+0x14) 1/r32/ecx
11306     89/<- *edi 1/r32/ecx
11307     8b/-> *(ebp+0x18) 1/r32/ecx
11308     89/<- *(edi+4) 1/r32/ecx
11309 $append-stmt-var:end:
11310     # . restore registers
11311     5f/pop-to-edi
11312     59/pop-to-ecx
11313     58/pop-to-eax
11314     # . epilogue
11315     89/<- %esp 5/r32/ebp
11316     5d/pop-to-ebp
11317     c3/return
11318 
11319 append-to-block:  # ad: (addr allocation-descriptor), block: (addr block), x: (handle stmt)
11320     # . prologue
11321     55/push-ebp
11322     89/<- %ebp 4/r32/esp
11323     # . save registers
11324     50/push-eax
11325     56/push-esi
11326     # esi = block
11327     8b/-> *(ebp+0xc) 6/r32/esi
11328     # block->stmts = append(x, block->stmts)
11329     8d/copy-address *(esi+4) 0/r32/eax  # Block-stmts
11330     (append-list *(ebp+8)  *(ebp+0x10) *(ebp+0x14)  *(esi+4) *(esi+8)  %eax)  # ad, x, x, Block-stmts, Block-stmts
11331 $append-to-block:end:
11332     # . restore registers
11333     5e/pop-to-esi
11334     58/pop-to-eax
11335     # . epilogue
11336     89/<- %esp 5/r32/ebp
11337     5d/pop-to-ebp
11338     c3/return
11339 
11340 ## Parsing types
11341 # We need to create metadata on user-defined types, and we need to use this
11342 # metadata as we parse instructions.
11343 # However, we also want to allow types to be used before their definitions.
11344 # This means we can't ever assume any type data structures exist.
11345 
11346 lookup-or-create-constant:  # container: (addr stmt-var), field-name: (addr slice), out: (addr handle var)
11347     # . prologue
11348     55/push-ebp
11349     89/<- %ebp 4/r32/esp
11350     # . save registers
11351     50/push-eax
11352     56/push-esi
11353     # var container-type/esi: type-id
11354     (container-type *(ebp+8))  # => eax
11355     89/<- %esi 0/r32/eax
11356     # var tmp/eax: (handle typeinfo) = find-or-create-typeinfo(container-type)
11357     68/push 0/imm32
11358     68/push 0/imm32
11359     89/<- %eax 4/r32/esp
11360     (find-or-create-typeinfo %esi %eax)
11361     # var tmp-addr/eax: (addr typeinfo) = lookup(tmp)
11362     (lookup *eax *(eax+4))  # => eax
11363     # result = find-or-create-typeinfo-output-var(typeinfo, field-name)
11364 #?     (write-buffered Stderr "constant: ")
11365 #?     (write-slice-buffered Stderr *(ebp+0xc))
11366 #?     (write-buffered Stderr Newline)
11367 #?     (flush Stderr)
11368     (find-or-create-typeinfo-output-var %eax *(ebp+0xc) *(ebp+0x10))
11369 #?     8b/-> *(ebp+0x10) 0/r32/eax
11370 #?     (write-buffered Stderr "@")
11371 #?     (lookup *eax *(eax+4))
11372 #?     (write-int32-hex-buffered Stderr %eax)
11373 #?     (lookup *eax *(eax+4))
11374 #?     (write-buffered Stderr %eax)
11375 #?     (write-buffered Stderr Newline)
11376 #?     (flush Stderr)
11377 #?     (write-buffered Stderr "offset: ")
11378 #?     8b/-> *(eax+0x14) 0/r32/eax
11379 #?     (write-int32-hex-buffered Stderr %eax)
11380 #?     (write-buffered Stderr Newline)
11381 #?     (flush Stderr)
11382 $lookup-or-create-constant:end:
11383     # . reclaim locals
11384     81 0/subop/add %esp 8/imm32
11385     # . restore registers
11386     5e/pop-to-esi
11387     58/pop-to-eax
11388     # . epilogue
11389     89/<- %esp 5/r32/ebp
11390     5d/pop-to-ebp
11391     c3/return
11392 
11393 # if addr var:
11394 #   container->var->type->right->left->value
11395 # otherwise
11396 #   container->var->type->value
11397 container-type:  # container: (addr stmt-var) -> result/eax: type-id
11398     # . prologue
11399     55/push-ebp
11400     89/<- %ebp 4/r32/esp
11401     #
11402     8b/-> *(ebp+8) 0/r32/eax
11403     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11404     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11405     {
11406       81 7/subop/compare *(eax+8) 0/imm32  # Type-tree-right
11407       74/jump-if-= break/disp8
11408       (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
11409       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
11410     }
11411     8b/-> *(eax+4) 0/r32/eax  # Type-tree-value
11412 $container-type:end:
11413     # . epilogue
11414     89/<- %esp 5/r32/ebp
11415     5d/pop-to-ebp
11416     c3/return
11417 
11418 is-container?:  # t: type-id -> result/eax: boolean
11419     # . prologue
11420     55/push-ebp
11421     89/<- %ebp 4/r32/esp
11422     #
11423     8b/-> *(ebp+8) 0/r32/eax
11424     c1/shift 4/subop/left %eax 2/imm8
11425     3b/compare 0/r32/eax *Primitive-type-ids
11426     0f 9d/set-if->= %al
11427     81 4/subop/and %eax 0xff/imm32
11428 $is-container?:end:
11429     # . epilogue
11430     89/<- %esp 5/r32/ebp
11431     5d/pop-to-ebp
11432     c3/return
11433 
11434 find-or-create-typeinfo:  # t: type-id, out: (addr handle typeinfo)
11435     # . prologue
11436     55/push-ebp
11437     89/<- %ebp 4/r32/esp
11438     # . save registers
11439     50/push-eax
11440     51/push-ecx
11441     52/push-edx
11442     57/push-edi
11443     # edi = out
11444     8b/-> *(ebp+0xc) 7/r32/edi
11445     # var fields/ecx: (handle table (handle array byte) (handle typeinfo-entry))
11446     68/push 0/imm32
11447     68/push 0/imm32
11448     89/<- %ecx 4/r32/esp
11449     # find-typeinfo(t, out)
11450     (find-typeinfo *(ebp+8) %edi)
11451     {
11452       # if (*out != 0) break
11453       81 7/subop/compare *edi 0/imm32
11454       0f 85/jump-if-!= break/disp32
11455 $find-or-create-typeinfo:create:
11456       # *out = allocate
11457       (allocate Heap *Typeinfo-size %edi)
11458       # var tmp/eax: (addr typeinfo) = lookup(*out)
11459       (lookup *edi *(edi+4))  # => eax
11460 #?     (write-buffered Stderr "created typeinfo at ")
11461 #?     (write-int32-hex-buffered Stderr %eax)
11462 #?     (write-buffered Stderr " for type-id ")
11463 #?     (write-int32-hex-buffered Stderr *(ebp+8))
11464 #?     (write-buffered Stderr Newline)
11465 #?     (flush Stderr)
11466       # tmp->id = t
11467       8b/-> *(ebp+8) 2/r32/edx
11468       89/<- *eax 2/r32/edx  # Typeinfo-id
11469       # tmp->fields = new table
11470       # . fields = new table
11471       (new-stream Heap 0x40 *Typeinfo-fields-row-size %ecx)
11472       # . tmp->fields = fields
11473       8b/-> *ecx 2/r32/edx
11474       89/<- *(eax+4) 2/r32/edx  # Typeinfo-fields
11475       8b/-> *(ecx+4) 2/r32/edx
11476       89/<- *(eax+8) 2/r32/edx  # Typeinfo-fields
11477       # tmp->next = Program->types
11478       8b/-> *_Program-types 1/r32/ecx
11479       89/<- *(eax+0x10) 1/r32/ecx  # Typeinfo-next
11480       8b/-> *_Program-types->payload 1/r32/ecx
11481       89/<- *(eax+0x14) 1/r32/ecx  # Typeinfo-next
11482       # Program->types = out
11483       8b/-> *edi 1/r32/ecx
11484       89/<- *_Program-types 1/r32/ecx
11485       8b/-> *(edi+4) 1/r32/ecx
11486       89/<- *_Program-types->payload 1/r32/ecx
11487     }
11488 $find-or-create-typeinfo:end:
11489     # . reclaim locals
11490     81 0/subop/add %esp 8/imm32
11491     # . restore registers
11492     5f/pop-to-edi
11493     5a/pop-to-edx
11494     59/pop-to-ecx
11495     58/pop-to-eax
11496     # . epilogue
11497     89/<- %esp 5/r32/ebp
11498     5d/pop-to-ebp
11499     c3/return
11500 
11501 find-typeinfo:  # t: type-id, out: (addr handle typeinfo)
11502     # . prologue
11503     55/push-ebp
11504     89/<- %ebp 4/r32/esp
11505     # . save registers
11506     50/push-eax
11507     51/push-ecx
11508     52/push-edx
11509     57/push-edi
11510     # ecx = t
11511     8b/-> *(ebp+8) 1/r32/ecx
11512     # edi = out
11513     8b/-> *(ebp+0xc) 7/r32/edi
11514     # *out = Program->types
11515     8b/-> *_Program-types 0/r32/eax
11516     89/<- *edi 0/r32/eax
11517     8b/-> *_Program-types->payload 0/r32/eax
11518     89/<- *(edi+4) 0/r32/eax
11519     {
11520 $find-typeinfo:loop:
11521       # if (*out == 0) break
11522       81 7/subop/compare *edi 0/imm32
11523       74/jump-if-= break/disp8
11524 $find-typeinfo:check:
11525       # var tmp/eax: (addr typeinfo) = lookup(*out)
11526       (lookup *edi *(edi+4))  # => eax
11527       # if (tmp->id == t) break
11528       39/compare *eax 1/r32/ecx  # Typeinfo-id
11529       74/jump-if-= break/disp8
11530 $find-typeinfo:continue:
11531       # *out = tmp->next
11532       8b/-> *(eax+0x10) 2/r32/edx  # Typeinfo-next
11533       89/<- *edi 2/r32/edx
11534       8b/-> *(eax+0x14) 2/r32/edx  # Typeinfo-next
11535       89/<- *(edi+4) 2/r32/edx
11536       #
11537       eb/jump loop/disp8
11538     }
11539 $find-typeinfo:end:
11540     # . restore registers
11541     5f/pop-to-edi
11542     5a/pop-to-edx
11543     59/pop-to-ecx
11544     58/pop-to-eax
11545     # . epilogue
11546     89/<- %esp 5/r32/ebp
11547     5d/pop-to-ebp
11548     c3/return
11549 
11550 find-or-create-typeinfo-output-var:  # T: (addr typeinfo), f: (addr slice), out: (addr handle var)
11551     # . prologue
11552     55/push-ebp
11553     89/<- %ebp 4/r32/esp
11554     # . save registers
11555     50/push-eax
11556     52/push-edx
11557     57/push-edi
11558     # var dest/edi: (handle typeinfo-entry)
11559     68/push 0/imm32
11560     68/push 0/imm32
11561     89/<- %edi 4/r32/esp
11562     # find-or-create-typeinfo-fields(T, f, dest)
11563     (find-or-create-typeinfo-fields *(ebp+8) *(ebp+0xc) %edi)
11564     # var dest-addr/edi: (addr typeinfo-entry) = lookup(dest)
11565     (lookup *edi *(edi+4))  # => eax
11566     89/<- %edi 0/r32/eax
11567     # if dest-addr->output-var doesn't exist, create it
11568     {
11569       81 7/subop/compare *(edi+0xc) 0/imm32  # Typeinfo-entry-output-var
11570       0f 85/jump-if-!= break/disp32
11571       # dest-addr->output-var = new var(dummy name, type, -1 offset)
11572       # . var name/eax: (handle array byte) = "field"
11573       68/push 0/imm32
11574       68/push 0/imm32
11575       89/<- %eax 4/r32/esp
11576       (slice-to-string Heap *(ebp+0xc) %eax)
11577       # . new var
11578       8d/copy-address *(edi+0xc) 2/r32/edx
11579       (new-var Heap  *eax *(eax+4)  %edx)
11580       # . reclaim name
11581       81 0/subop/add %esp 8/imm32
11582       # var result/edx: (addr var) = lookup(dest-addr->output-var)
11583       (lookup *(edi+0xc) *(edi+0x10))  # => eax
11584       89/<- %edx 0/r32/eax
11585       # result->type = new constant type
11586       8d/copy-address *(edx+8) 0/r32/eax  # Var-type
11587       (allocate Heap *Type-tree-size %eax)
11588       (lookup *(edx+8) *(edx+0xc))  # => eax
11589       c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
11590       c7 0/subop/copy *(eax+4) 6/imm32/constant  # Type-tree-value
11591       c7 0/subop/copy *(eax+8) 0/imm32  # Type-tree-left
11592       c7 0/subop/copy *(eax+0xc) 0/imm32  # Type-tree-right
11593       c7 0/subop/copy *(eax+0x10) 0/imm32  # Type-tree-right
11594       # result->offset isn't filled out yet
11595       c7 0/subop/copy *(edx+0x14) -1/imm32/uninitialized  # Var-offset
11596     }
11597     # out = dest-addr->output-var
11598     8b/-> *(ebp+0x10) 2/r32/edx
11599     8b/-> *(edi+0xc) 0/r32/eax  # Typeinfo-entry-output-var
11600     89/<- *edx 0/r32/eax
11601     8b/-> *(edi+0x10) 0/r32/eax  # Typeinfo-entry-output-var
11602     89/<- *(edx+4) 0/r32/eax
11603 $find-or-create-typeinfo-output-var:end:
11604     # . reclaim locals
11605     81 0/subop/add %esp 8/imm32
11606     # . restore registers
11607     5f/pop-to-edi
11608     5a/pop-to-edx
11609     58/pop-to-eax
11610     # . epilogue
11611     89/<- %esp 5/r32/ebp
11612     5d/pop-to-ebp
11613     c3/return
11614 
11615 find-or-create-typeinfo-fields:  # T: (addr typeinfo), f: (addr slice), out: (addr handle typeinfo-entry)
11616     # . prologue
11617     55/push-ebp
11618     89/<- %ebp 4/r32/esp
11619     # . save registers
11620     50/push-eax
11621     56/push-esi
11622     57/push-edi
11623     # eax = lookup(T->fields)
11624     8b/-> *(ebp+8) 0/r32/eax
11625     (lookup *(eax+4) *(eax+8))  # Typeinfo-fields Typeinfo-fields => eax
11626     # edi = out
11627     8b/-> *(ebp+0x10) 7/r32/edi
11628     # var src/esi: (addr handle typeinfo-entry) = get-or-insert-slice(T->fields, f)
11629     (get-or-insert-slice %eax *(ebp+0xc) *Typeinfo-fields-row-size Heap)  # => eax
11630     89/<- %esi 0/r32/eax
11631     # if src doesn't exist, allocate it
11632     {
11633       81 7/subop/compare *esi 0/imm32
11634       75/jump-if-!= break/disp8
11635       (allocate Heap *Typeinfo-entry-size %esi)
11636 #?       (write-buffered Stderr "handle at ")
11637 #?       (write-int32-hex-buffered Stderr %esi)
11638 #?       (write-buffered Stderr ": ")
11639 #?       (write-int32-hex-buffered Stderr *esi)
11640 #?       (write-buffered Stderr " ")
11641 #?       (write-int32-hex-buffered Stderr *(esi+4))
11642 #?       (write-buffered Stderr Newline)
11643 #?       (flush Stderr)
11644 #?       (lookup *esi *(esi+4))
11645 #?       (write-buffered Stderr "created typeinfo fields at ")
11646 #?       (write-int32-hex-buffered Stderr %esi)
11647 #?       (write-buffered Stderr " for ")
11648 #?       (write-int32-hex-buffered Stderr *(ebp+8))
11649 #?       (write-buffered Stderr Newline)
11650 #?       (flush Stderr)
11651     }
11652     # *out = src
11653     # . *edi = *src
11654     8b/-> *esi 0/r32/eax
11655     89/<- *edi 0/r32/eax
11656     8b/-> *(esi+4) 0/r32/eax
11657     89/<- *(edi+4) 0/r32/eax
11658 $find-or-create-typeinfo-fields:end:
11659     # . restore registers
11660     5f/pop-to-edi
11661     5e/pop-to-esi
11662     58/pop-to-eax
11663     # . epilogue
11664     89/<- %esp 5/r32/ebp
11665     5d/pop-to-ebp
11666     c3/return
11667 
11668 populate-mu-type:  # in: (addr stream byte), t: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
11669     # pseudocode:
11670     #   var line: (stream byte 512)
11671     #   curr-index = 0
11672     #   while true
11673     #     clear-stream(line)
11674     #     read-line-buffered(in, line)
11675     #     if line->write == 0
11676     #       abort
11677     #     word-slice = next-mu-token(line)
11678     #     if slice-empty?(word-slice)               # end of line
11679     #       continue
11680     #     if slice-equal?(word-slice, "}")
11681     #       break
11682     #     var v: (handle var) = parse-var-with-type(word-slice, line)
11683     #     var r: (handle typeinfo-fields) = find-or-create-typeinfo-fields(t, word-slice/v->name)
11684     #     TODO: ensure that r->first is null
11685     #     r->index = curr-index
11686     #     curr-index++
11687     #     r->input-var = v
11688     #     if r->output-var == 0
11689     #       r->output-var = new literal
11690     #     TODO: ensure nothing else in line
11691     # t->total-size-in-bytes = -2 (not yet initialized)
11692     #
11693     # . prologue
11694     55/push-ebp
11695     89/<- %ebp 4/r32/esp
11696     # var curr-index: int at *(ebp-4)
11697     68/push 0/imm32
11698     # . save registers
11699     50/push-eax
11700     51/push-ecx
11701     52/push-edx
11702     53/push-ebx
11703     56/push-esi
11704     57/push-edi
11705     # edi = t
11706     8b/-> *(ebp+0xc) 7/r32/edi
11707     # var line/ecx: (stream byte 512)
11708     81 5/subop/subtract %esp 0x200/imm32
11709     68/push 0x200/imm32/size
11710     68/push 0/imm32/read
11711     68/push 0/imm32/write
11712     89/<- %ecx 4/r32/esp
11713     # var word-slice/edx: slice
11714     68/push 0/imm32/end
11715     68/push 0/imm32/start
11716     89/<- %edx 4/r32/esp
11717     # var v/esi: (handle var)
11718     68/push 0/imm32
11719     68/push 0/imm32
11720     89/<- %esi 4/r32/esp
11721     # var r/ebx: (handle typeinfo-entry)
11722     68/push 0/imm32
11723     68/push 0/imm32
11724     89/<- %ebx 4/r32/esp
11725     {
11726 $populate-mu-type:line-loop:
11727       (clear-stream %ecx)
11728       (read-line-buffered *(ebp+8) %ecx)
11729       # if (line->write == 0) abort
11730       81 7/subop/compare *ecx 0/imm32
11731       0f 84/jump-if-= $populate-mu-type:error1/disp32
11732 +--  6 lines: #?       # dump line ------------------------------------------------------------------------------------------------------------------------------------------------------
11738       (next-mu-token %ecx %edx)
11739       # if slice-empty?(word-slice) continue
11740       (slice-empty? %edx)  # => eax
11741       3d/compare-eax-and 0/imm32
11742       0f 85/jump-if-!= loop/disp32
11743       # if slice-equal?(word-slice, "}") break
11744       (slice-equal? %edx "}")
11745       3d/compare-eax-and 0/imm32
11746       0f 85/jump-if-!= break/disp32
11747 $populate-mu-type:parse-element:
11748       # v = parse-var-with-type(word-slice, first-line)
11749       # must do this first to strip the trailing ':' from word-slice before
11750       # using it in find-or-create-typeinfo-fields below
11751       # TODO: clean up that mutation in parse-var-with-type
11752       (parse-var-with-type %edx %ecx %esi *(ebp+0x10) *(ebp+0x14))
11753       # if v is an addr, abort
11754       (lookup *esi *(esi+4))  # => eax
11755       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11756       (is-mu-addr-type? %eax)  # => eax
11757       3d/compare-eax-and 0/imm32/false
11758       0f 85/jump-if-!= $populate-mu-type:error2/disp32
11759       # if v is an array, abort  (we could support it, but initialization gets complex)
11760       (lookup *esi *(esi+4))  # => eax
11761       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11762       (is-mu-array-type? %eax)  # => eax
11763       3d/compare-eax-and 0/imm32/false
11764       0f 85/jump-if-!= $populate-mu-type:error3/disp32
11765       # if v is a byte, abort
11766       (lookup *esi *(esi+4))  # => eax
11767       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11768       (is-simple-mu-type? %eax 8)  # byte => eax
11769       3d/compare-eax-and 0/imm32/false
11770       0f 85/jump-if-!= $populate-mu-type:error4/disp32
11771       # if v is a slice, abort
11772       (lookup *esi *(esi+4))  # => eax
11773       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11774       (is-simple-mu-type? %eax 0xc)  # slice => eax
11775       3d/compare-eax-and 0/imm32/false
11776       0f 85/jump-if-!= $populate-mu-type:error5/disp32
11777       # if v is a stream, abort  (we could support it, but initialization gets even more complex)
11778       (lookup *esi *(esi+4))  # => eax
11779       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11780       (is-mu-stream-type? %eax)  # => eax
11781       3d/compare-eax-and 0/imm32/false
11782       0f 85/jump-if-!= $populate-mu-type:error6/disp32
11783       # var tmp/ecx
11784       51/push-ecx
11785 $populate-mu-type:create-typeinfo-fields:
11786       # var r/ebx: (handle typeinfo-entry)
11787       (find-or-create-typeinfo-fields %edi %edx %ebx)
11788       # r->index = curr-index
11789       (lookup *ebx *(ebx+4))  # => eax
11790       8b/-> *(ebp-4) 1/r32/ecx
11791 #?       (write-buffered Stderr "saving index ")
11792 #?       (write-int32-hex-buffered Stderr %ecx)
11793 #?       (write-buffered Stderr " at ")
11794 #?       (write-int32-hex-buffered Stderr %edi)
11795 #?       (write-buffered Stderr Newline)
11796 #?       (flush Stderr)
11797       89/<- *(eax+8) 1/r32/ecx  # Typeinfo-entry-index
11798       # ++curr-index
11799       ff 0/subop/increment *(ebp-4)
11800 $populate-mu-type:set-input-type:
11801       # r->input-var = v
11802       8b/-> *esi 1/r32/ecx
11803       89/<- *eax 1/r32/ecx  # Typeinfo-entry-input-var
11804       8b/-> *(esi+4) 1/r32/ecx
11805       89/<- *(eax+4) 1/r32/ecx  # Typeinfo-entry-input-var
11806       # restore line
11807       59/pop-to-ecx
11808       {
11809 $populate-mu-type:create-output-type:
11810         # if (r->output-var == 0) create a new var with some placeholder data
11811         81 7/subop/compare *(eax+0xc) 0/imm32  # Typeinfo-entry-output-var
11812         75/jump-if-!= break/disp8
11813         8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
11814         (new-literal Heap %edx %eax)
11815       }
11816       e9/jump loop/disp32
11817     }
11818 $populate-mu-type:invalidate-total-size-in-bytes:
11819     # Offsets and total size may not be accurate here since we may not yet
11820     # have encountered the element types.
11821     # We'll recompute them separately after parsing the entire program.
11822     c7 0/subop/copy *(edi+0xc) -2/imm32/uninitialized  # Typeinfo-total-size-in-bytes
11823 $populate-mu-type:end:
11824     # . reclaim locals
11825     81 0/subop/add %esp 0x224/imm32
11826     # . restore registers
11827     5f/pop-to-edi
11828     5e/pop-to-esi
11829     5b/pop-to-ebx
11830     5a/pop-to-edx
11831     59/pop-to-ecx
11832     58/pop-to-eax
11833     # reclaim curr-index
11834     81 0/subop/add %esp 4/imm32
11835     # . epilogue
11836     89/<- %esp 5/r32/ebp
11837     5d/pop-to-ebp
11838     c3/return
11839 
11840 $populate-mu-type:error1:
11841     # error("incomplete type definition '" t->name "'\n")
11842     (write-buffered *(ebp+0x10) "incomplete type definition '")
11843     (type-name *edi)  # Typeinfo-id => eax
11844     (write-buffered *(ebp+0x10) %eax)
11845     (write-buffered *(ebp+0x10) "\n")
11846     (flush *(ebp+0x10))
11847     (stop *(ebp+0x14) 1)
11848     # never gets here
11849 
11850 $populate-mu-type:error2:
11851     (write-buffered *(ebp+0x10) "type ")
11852     (type-name *edi)  # Typeinfo-id => eax
11853     (write-buffered *(ebp+0x10) %eax)
11854     (write-buffered *(ebp+0x10) ": 'addr' elements not allowed\n")
11855     (flush *(ebp+0x10))
11856     (stop *(ebp+0x14) 1)
11857     # never gets here
11858 
11859 $populate-mu-type:error3:
11860     (write-buffered *(ebp+0x10) "type ")
11861     (type-name *edi)  # Typeinfo-id => eax
11862     (write-buffered *(ebp+0x10) %eax)
11863     (write-buffered *(ebp+0x10) ": 'array' elements not allowed for now\n")
11864     (flush *(ebp+0x10))
11865     (stop *(ebp+0x14) 1)
11866     # never gets here
11867 
11868 $populate-mu-type:error4:
11869     (write-buffered *(ebp+0x10) "type ")
11870     (type-name *edi)  # Typeinfo-id => eax
11871     (write-buffered *(ebp+0x10) %eax)
11872     (write-buffered *(ebp+0x10) ": 'byte' elements not allowed\n")
11873     (flush *(ebp+0x10))
11874     (stop *(ebp+0x14) 1)
11875     # never gets here
11876 
11877 $populate-mu-type:error5:
11878     (write-buffered *(ebp+0x10) "type ")
11879     (type-name *edi)  # Typeinfo-id => eax
11880     (write-buffered *(ebp+0x10) %eax)
11881     (write-buffered *(ebp+0x10) ": 'slice' elements not allowed\n")
11882     (flush *(ebp+0x10))
11883     (stop *(ebp+0x14) 1)
11884     # never gets here
11885 
11886 $populate-mu-type:error6:
11887     (write-buffered *(ebp+0x10) "type ")
11888     (type-name *edi)  # Typeinfo-id => eax
11889     (write-buffered *(ebp+0x10) %eax)
11890     (write-buffered *(ebp+0x10) ": 'stream' elements not allowed for now\n")
11891     (flush *(ebp+0x10))
11892     (stop *(ebp+0x14) 1)
11893     # never gets here
11894 
11895 type-name:  # index: int -> result/eax: (addr array byte)
11896     # . prologue
11897     55/push-ebp
11898     89/<- %ebp 4/r32/esp
11899     #
11900     (index Type-id *(ebp+8))
11901 $type-name:end:
11902     # . epilogue
11903     89/<- %esp 5/r32/ebp
11904     5d/pop-to-ebp
11905     c3/return
11906 
11907 index:  # arr: (addr stream (handle array byte)), index: int -> result/eax: (addr array byte)
11908     # . prologue
11909     55/push-ebp
11910     89/<- %ebp 4/r32/esp
11911     # . save registers
11912     56/push-esi
11913     # TODO: bounds-check index
11914     # esi = arr
11915     8b/-> *(ebp+8) 6/r32/esi
11916     # eax = index
11917     8b/-> *(ebp+0xc) 0/r32/eax
11918     # eax = *(arr + 12 + index)
11919     8b/-> *(esi+eax<<2+0xc) 0/r32/eax
11920 $index:end:
11921     # . restore registers
11922     5e/pop-to-esi
11923     # . epilogue
11924     89/<- %esp 5/r32/ebp
11925     5d/pop-to-ebp
11926     c3/return
11927 
11928 #######################################################
11929 # Compute type sizes
11930 #######################################################
11931 
11932 # Compute the sizes of all user-defined types.
11933 # We'll need the sizes of their elements, which may be other user-defined
11934 # types, which we will compute as needed.
11935 
11936 # Initially, all user-defined types have their sizes set to -2 (invalid)
11937 populate-mu-type-sizes:  # err: (addr buffered-file), ed: (addr exit-descriptor)
11938     # . prologue
11939     55/push-ebp
11940     89/<- %ebp 4/r32/esp
11941 $populate-mu-type-sizes:total-sizes:
11942     # var curr/eax: (addr typeinfo) = lookup(Program->types)
11943     (lookup *_Program-types *_Program-types->payload)  # => eax
11944     {
11945       # if (curr == null) break
11946       3d/compare-eax-and 0/imm32/null
11947       74/jump-if-= break/disp8
11948       (populate-mu-type-sizes-in-type %eax *(ebp+8) *(ebp+0xc))
11949       # curr = lookup(curr->next)
11950       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
11951       eb/jump loop/disp8
11952     }
11953 $populate-mu-type-sizes:offsets:
11954     # curr = *Program->types
11955     (lookup *_Program-types *_Program-types->payload)  # => eax
11956     {
11957       # if (curr == null) break
11958       3d/compare-eax-and 0/imm32/null
11959       74/jump-if-= break/disp8
11960       (populate-mu-type-offsets %eax *(ebp+8) *(ebp+0xc))
11961       # curr = curr->next
11962       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
11963       eb/jump loop/disp8
11964     }
11965 $populate-mu-type-sizes:end:
11966     # . epilogue
11967     89/<- %esp 5/r32/ebp
11968     5d/pop-to-ebp
11969     c3/return
11970 
11971 # compute sizes of all fields, recursing as necessary
11972 # sum up all their sizes to arrive at total size
11973 # fields may be out of order, but that doesn't affect the answer
11974 populate-mu-type-sizes-in-type:  # T: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
11975     # . prologue
11976     55/push-ebp
11977     89/<- %ebp 4/r32/esp
11978     # . save registers
11979     50/push-eax
11980     51/push-ecx
11981     52/push-edx
11982     56/push-esi
11983     57/push-edi
11984     # esi = T
11985     8b/-> *(ebp+8) 6/r32/esi
11986     # if T is already computed, return
11987     81 7/subop/compare *(esi+0xc) 0/imm32  # Typeinfo-total-size-in-bytes
11988     0f 8d/jump-if->= $populate-mu-type-sizes-in-type:end/disp32
11989     # if T is being computed, abort
11990     81 7/subop/compare *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
11991     0f 84/jump-if-= $populate-mu-type-sizes-in-type:abort/disp32
11992     # tag T (-2 to -1) to avoid infinite recursion
11993     c7 0/subop/copy *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
11994     # var total-size/edi: int = 0
11995     bf/copy-to-edi 0/imm32
11996     # - for every field, if it's a user-defined type, compute its size
11997     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
11998     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
11999     89/<- %ecx 0/r32/eax
12000     # var table-size/edx: int = table->write
12001     8b/-> *ecx 2/r32/edx  # stream-write
12002     # var curr/ecx: (addr table_row) = table->data
12003     8d/copy-address *(ecx+0xc) 1/r32/ecx
12004     # var max/edx: (addr table_row) = table->data + table->write
12005     8d/copy-address *(ecx+edx) 2/r32/edx
12006     {
12007 $populate-mu-type-sizes-in-type:loop:
12008       # if (curr >= max) break
12009       39/compare %ecx 2/r32/edx
12010       73/jump-if-addr>= break/disp8
12011       # var t/eax: (addr typeinfo-entry) = lookup(curr->value)
12012       (lookup *(ecx+8) *(ecx+0xc))  # => eax
12013       # if (t->input-var == 0) silently ignore it; we'll emit a nice error message while type-checking
12014       81 7/subop/compare *eax 0/imm32  # Typeinfo-entry-input-var
12015       74/jump-if-= $populate-mu-type-sizes-in-type:end/disp8
12016       # compute size of t->input-var
12017       (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
12018       (compute-size-of-var %eax *(ebp+0xc) *(ebp+0x10))  # => eax
12019       # result += eax
12020       01/add-to %edi 0/r32/eax
12021       # curr += row-size
12022       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
12023       #
12024       eb/jump loop/disp8
12025     }
12026     # - save result
12027     89/<- *(esi+0xc) 7/r32/edi  # Typeinfo-total-size-in-bytes
12028 $populate-mu-type-sizes-in-type:end:
12029     # . restore registers
12030     5f/pop-to-edi
12031     5e/pop-to-esi
12032     5a/pop-to-edx
12033     59/pop-to-ecx
12034     58/pop-to-eax
12035     # . epilogue
12036     89/<- %esp 5/r32/ebp
12037     5d/pop-to-ebp
12038     c3/return
12039 
12040 $populate-mu-type-sizes-in-type:abort:
12041     (write-buffered *(ebp+0xc) "cycle in type definitions\n")
12042     (flush *(ebp+0xc))
12043     (stop *(ebp+0x10) 1)
12044     # never gets here
12045 
12046 # Analogous to size-of, except we need to compute what size-of can just read
12047 # off the right data structures.
12048 compute-size-of-var:  # in: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
12049     # . prologue
12050     55/push-ebp
12051     89/<- %ebp 4/r32/esp
12052     # . push registers
12053     51/push-ecx
12054     # var t/ecx: (addr type-tree) = lookup(v->type)
12055     8b/-> *(ebp+8) 1/r32/ecx
12056     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
12057     89/<- %ecx 0/r32/eax
12058     # if (t->is-atom == false) t = lookup(t->left)
12059     {
12060       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
12061       75/jump-if-!= break/disp8
12062       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
12063       89/<- %ecx 0/r32/eax
12064     }
12065     # TODO: ensure t is an atom
12066     (compute-size-of-type-id *(ecx+4) *(ebp+0xc) *(ebp+0x10))  # Type-tree-value => eax
12067 $compute-size-of-var:end:
12068     # . restore registers
12069     59/pop-to-ecx
12070     # . epilogue
12071     89/<- %esp 5/r32/ebp
12072     5d/pop-to-ebp
12073     c3/return
12074 
12075 compute-size-of-type-id:  # t: type-id, err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
12076     # . prologue
12077     55/push-ebp
12078     89/<- %ebp 4/r32/esp
12079     # . save registers
12080     51/push-ecx
12081     # var out/ecx: (handle typeinfo)
12082     68/push 0/imm32
12083     68/push 0/imm32
12084     89/<- %ecx 4/r32/esp
12085     # eax = t
12086     8b/-> *(ebp+8) 0/r32/eax
12087     # if t is a literal, return 0
12088     3d/compare-eax-and 0/imm32/literal
12089     0f 84/jump-if-= $compute-size-of-type-id:end/disp32  # eax changes type from type-id to int
12090     # if t is a byte, return 4 (because we don't really support non-multiples of 4)
12091     3d/compare-eax-and 8/imm32/byte
12092     {
12093       75/jump-if-!= break/disp8
12094       b8/copy-to-eax 4/imm32
12095       eb/jump $compute-size-of-type-id:end/disp8
12096     }
12097     # if t is a handle, return 8
12098     3d/compare-eax-and 4/imm32/handle
12099     {
12100       75/jump-if-!= break/disp8
12101       b8/copy-to-eax 8/imm32
12102       eb/jump $compute-size-of-type-id:end/disp8  # eax changes type from type-id to int
12103     }
12104     # if t is a slice, return 8
12105     3d/compare-eax-and 0xc/imm32/slice
12106     {
12107       75/jump-if-!= break/disp8
12108       b8/copy-to-eax 8/imm32
12109       eb/jump $compute-size-of-type-id:end/disp8  # eax changes type from type-id to int
12110     }
12111     # if t is a user-defined type, compute its size
12112     # TODO: support non-atom type
12113     (find-typeinfo %eax %ecx)
12114     {
12115       81 7/subop/compare *ecx 0/imm32
12116       74/jump-if-= break/disp8
12117 $compute-size-of-type-id:user-defined:
12118       (lookup *ecx *(ecx+4))  # => eax
12119       (populate-mu-type-sizes-in-type %eax *(ebp+0xc) *(ebp+0x10))
12120       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
12121       eb/jump $compute-size-of-type-id:end/disp8
12122     }
12123     # otherwise return the word size
12124     b8/copy-to-eax 4/imm32
12125 $compute-size-of-type-id:end:
12126     # . reclaim locals
12127     81 0/subop/add %esp 8/imm32
12128     # . restore registers
12129     59/pop-to-ecx
12130     # . epilogue
12131     89/<- %esp 5/r32/ebp
12132     5d/pop-to-ebp
12133     c3/return
12134 
12135 # at this point we have total sizes for all user-defined types
12136 # compute offsets for each element
12137 # complication: fields may be out of order
12138 populate-mu-type-offsets:  # in: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
12139     # . prologue
12140     55/push-ebp
12141     89/<- %ebp 4/r32/esp
12142     # . save registers
12143     50/push-eax
12144     51/push-ecx
12145     52/push-edx
12146     53/push-ebx
12147     56/push-esi
12148     57/push-edi
12149 #?     (dump-typeinfos "aaa\n")
12150     # var curr-offset/edi: int = 0
12151     bf/copy-to-edi 0/imm32
12152     # var table/ecx: (addr table string_key (handle typeinfo-entry)) = lookup(in->fields)
12153     8b/-> *(ebp+8) 1/r32/ecx
12154     (lookup *(ecx+4) *(ecx+8))  # Typeinfo-fields Typeinfo-fields => eax
12155     89/<- %ecx 0/r32/eax
12156     # var num-elems/edx: int = table->write / Typeinfo-fields-row-size
12157     8b/-> *ecx 2/r32/edx  # stream-write
12158     c1 5/subop/shift-right-logical  %edx 4/imm8
12159     # var i/ebx: int = 0
12160     bb/copy-to-ebx 0/imm32
12161     {
12162 $populate-mu-type-offsets:loop:
12163       39/compare %ebx 2/r32/edx
12164       0f 8d/jump-if->= break/disp32
12165 #?       (write-buffered Stderr "looking up index ")
12166 #?       (write-int32-hex-buffered Stderr %ebx)
12167 #?       (write-buffered Stderr " in ")
12168 #?       (write-int32-hex-buffered Stderr *(ebp+8))
12169 #?       (write-buffered Stderr Newline)
12170 #?       (flush Stderr)
12171       # var v/esi: (addr typeinfo-entry)
12172       (locate-typeinfo-entry-with-index %ecx %ebx *(ebp+0xc) *(ebp+0x10))  # => eax
12173       89/<- %esi 0/r32/eax
12174       # if v is null, silently move on; we'll emit a nice error message while type-checking
12175       81 7/subop/compare %esi 0/imm32  # Typeinfo-entry-input-var
12176       74/jump-if-= $populate-mu-type-offsets:end/disp8
12177       # if (v->input-var == 0) silently ignore v; we'll emit a nice error message while type-checking
12178       81 7/subop/compare *esi 0/imm32  # Typeinfo-entry-input-var
12179       74/jump-if-= $populate-mu-type-offsets:end/disp8
12180       # v->output-var->offset = curr-offset
12181       # . eax: (addr var)
12182       (lookup *(esi+0xc) *(esi+0x10))  # Typeinfo-entry-output-var Typeinfo-entry-output-var => eax
12183       89/<- *(eax+0x14) 7/r32/edi  # Var-offset
12184       # curr-offset += size-of(v->input-var)
12185       (lookup *esi *(esi+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
12186       (size-of %eax)  # => eax
12187       01/add-to %edi 0/r32/eax
12188       # ++i
12189       43/increment-ebx
12190       e9/jump loop/disp32
12191     }
12192 $populate-mu-type-offsets:end:
12193     # . restore registers
12194     5f/pop-to-edi
12195     5e/pop-to-esi
12196     5b/pop-to-ebx
12197     5a/pop-to-edx
12198     59/pop-to-ecx
12199     58/pop-to-eax
12200     # . epilogue
12201     89/<- %esp 5/r32/ebp
12202     5d/pop-to-ebp
12203     c3/return
12204 
12205 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)
12206     # . prologue
12207     55/push-ebp
12208     89/<- %ebp 4/r32/esp
12209     # . save registers
12210     51/push-ecx
12211     52/push-edx
12212     53/push-ebx
12213     56/push-esi
12214     57/push-edi
12215     # esi = table
12216     8b/-> *(ebp+8) 6/r32/esi
12217     # var curr/ecx: (addr row (handle array byte) (handle typeinfo-entry)) = table->data
12218     8d/copy-address *(esi+0xc) 1/r32/ecx
12219     # var max/edx: (addr byte) = &table->data[table->write]
12220     8b/-> *esi 2/r32/edx
12221     8d/copy-address *(ecx+edx) 2/r32/edx
12222     {
12223 $locate-typeinfo-entry-with-index:loop:
12224       39/compare %ecx 2/r32/edx
12225       73/jump-if-addr>= break/disp8
12226       # var v/eax: (addr typeinfo-entry)
12227       (lookup *(ecx+8) *(ecx+0xc))  # => eax
12228       # if (v->index == idx) return v
12229       8b/-> *(eax+8) 3/r32/ebx  # Typeinfo-entry-index
12230 #?       (write-buffered Stderr "comparing ")
12231 #?       (write-int32-hex-buffered Stderr %ebx)
12232 #?       (write-buffered Stderr " and ")
12233 #?       (write-int32-hex-buffered Stderr *(ebp+0xc))
12234 #?       (write-buffered Stderr Newline)
12235 #?       (flush Stderr)
12236       39/compare *(ebp+0xc) 3/r32/ebx
12237       74/jump-if-= $locate-typeinfo-entry-with-index:end/disp8
12238       # curr += Typeinfo-entry-size
12239       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-entry-size
12240       #
12241       eb/jump loop/disp8
12242     }
12243     # return 0
12244     b8/copy-to-eax 0/imm32
12245 $locate-typeinfo-entry-with-index:end:
12246 #?     (write-buffered Stderr "returning ")
12247 #?     (write-int32-hex-buffered Stderr %eax)
12248 #?     (write-buffered Stderr Newline)
12249 #?     (flush Stderr)
12250     # . restore registers
12251     5f/pop-to-edi
12252     5e/pop-to-esi
12253     5b/pop-to-ebx
12254     5a/pop-to-edx
12255     59/pop-to-ecx
12256     # . epilogue
12257     89/<- %esp 5/r32/ebp
12258     5d/pop-to-ebp
12259     c3/return
12260 
12261 dump-typeinfos:  # hdr: (addr array byte)
12262     # . prologue
12263     55/push-ebp
12264     89/<- %ebp 4/r32/esp
12265     # . save registers
12266     50/push-eax
12267     #
12268     (write-buffered Stderr *(ebp+8))
12269     (flush Stderr)
12270     # var curr/eax: (addr typeinfo) = lookup(Program->types)
12271     (lookup *_Program-types *_Program-types->payload)  # => eax
12272     {
12273       # if (curr == null) break
12274       3d/compare-eax-and 0/imm32
12275       74/jump-if-= break/disp8
12276       (write-buffered Stderr "---\n")
12277       (flush Stderr)
12278       (dump-typeinfo %eax)
12279       # curr = lookup(curr->next)
12280       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
12281       eb/jump loop/disp8
12282     }
12283 $dump-typeinfos:end:
12284     # . restore registers
12285     58/pop-to-eax
12286     # . epilogue
12287     89/<- %esp 5/r32/ebp
12288     5d/pop-to-ebp
12289     c3/return
12290 
12291 dump-typeinfo:  # in: (addr typeinfo)
12292     # . prologue
12293     55/push-ebp
12294     89/<- %ebp 4/r32/esp
12295     # . save registers
12296     50/push-eax
12297     51/push-ecx
12298     52/push-edx
12299     53/push-ebx
12300     56/push-esi
12301     57/push-edi
12302     # esi = in
12303     8b/-> *(ebp+8) 6/r32/esi
12304     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
12305     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
12306     89/<- %ecx 0/r32/eax
12307     (write-buffered Stderr "id:")
12308     (write-int32-hex-buffered Stderr *esi)
12309     (write-buffered Stderr "\n")
12310     (write-buffered Stderr "fields @ ")
12311     (write-int32-hex-buffered Stderr %ecx)
12312     (write-buffered Stderr Newline)
12313     (flush Stderr)
12314     (write-buffered Stderr "  write: ")
12315     (write-int32-hex-buffered Stderr *ecx)
12316     (write-buffered Stderr Newline)
12317     (flush Stderr)
12318     (write-buffered Stderr "  read: ")
12319     (write-int32-hex-buffered Stderr *(ecx+4))
12320     (write-buffered Stderr Newline)
12321     (flush Stderr)
12322     (write-buffered Stderr "  size: ")
12323     (write-int32-hex-buffered Stderr *(ecx+8))
12324     (write-buffered Stderr Newline)
12325     (flush Stderr)
12326     # var table-size/edx: int = table->write
12327     8b/-> *ecx 2/r32/edx  # stream-write
12328     # var curr/ecx: (addr table_row) = table->data
12329     8d/copy-address *(ecx+0xc) 1/r32/ecx
12330     # var max/edx: (addr table_row) = table->data + table->write
12331     8d/copy-address *(ecx+edx) 2/r32/edx
12332     {
12333 $dump-typeinfo:loop:
12334       # if (curr >= max) break
12335       39/compare %ecx 2/r32/edx
12336       0f 83/jump-if-addr>= break/disp32
12337       (write-buffered Stderr "  row:\n")
12338       (write-buffered Stderr "    key: ")
12339       (write-int32-hex-buffered Stderr *ecx)
12340       (write-buffered Stderr ",")
12341       (write-int32-hex-buffered Stderr *(ecx+4))
12342       (write-buffered Stderr " = '")
12343       (lookup *ecx *(ecx+4))
12344       (write-buffered Stderr %eax)
12345       (write-buffered Stderr "' @ ")
12346       (write-int32-hex-buffered Stderr %eax)
12347       (write-buffered Stderr Newline)
12348       (flush Stderr)
12349       (write-buffered Stderr "    value: ")
12350       (write-int32-hex-buffered Stderr *(ecx+8))
12351       (write-buffered Stderr ",")
12352       (write-int32-hex-buffered Stderr *(ecx+0xc))
12353       (write-buffered Stderr " = typeinfo-entry@")
12354       (lookup *(ecx+8) *(ecx+0xc))
12355       (write-int32-hex-buffered Stderr %eax)
12356       (write-buffered Stderr Newline)
12357       (flush Stderr)
12358       (write-buffered Stderr "        input var@")
12359       (dump-var 5 %eax)
12360       (lookup *(ecx+8) *(ecx+0xc))
12361       (write-buffered Stderr "        index: ")
12362       (write-int32-hex-buffered Stderr *(eax+8))
12363       (write-buffered Stderr Newline)
12364       (flush Stderr)
12365       (write-buffered Stderr "        output var@")
12366       8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
12367       (dump-var 5 %eax)
12368       (flush Stderr)
12369       # curr += row-size
12370       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
12371       #
12372       e9/jump loop/disp32
12373     }
12374 $dump-typeinfo:end:
12375     # . restore registers
12376     5f/pop-to-edi
12377     5e/pop-to-esi
12378     5b/pop-to-ebx
12379     5a/pop-to-edx
12380     59/pop-to-ecx
12381     58/pop-to-eax
12382     # . epilogue
12383     89/<- %esp 5/r32/ebp
12384     5d/pop-to-ebp
12385     c3/return
12386 
12387 dump-var:  # indent: int, v: (addr handle var)
12388     # . prologue
12389     55/push-ebp
12390     89/<- %ebp 4/r32/esp
12391     # . save registers
12392     50/push-eax
12393     53/push-ebx
12394     # eax = v
12395     8b/-> *(ebp+0xc) 0/r32/eax
12396     #
12397     (write-int32-hex-buffered Stderr *eax)
12398     (write-buffered Stderr ",")
12399     (write-int32-hex-buffered Stderr *(eax+4))
12400     (write-buffered Stderr "->")
12401     (lookup *eax *(eax+4))
12402     (write-int32-hex-buffered Stderr %eax)
12403     (write-buffered Stderr Newline)
12404     (flush Stderr)
12405     {
12406       3d/compare-eax-and 0/imm32
12407       0f 84/jump-if-= break/disp32
12408       (emit-indent Stderr *(ebp+8))
12409       (write-buffered Stderr "name: ")
12410       89/<- %ebx 0/r32/eax
12411       (write-int32-hex-buffered Stderr *ebx)  # Var-name
12412       (write-buffered Stderr ",")
12413       (write-int32-hex-buffered Stderr *(ebx+4))  # Var-name
12414       (write-buffered Stderr "->")
12415       (lookup *ebx *(ebx+4))  # Var-name
12416       (write-int32-hex-buffered Stderr %eax)
12417       {
12418         3d/compare-eax-and 0/imm32
12419         74/jump-if-= break/disp8
12420         (write-buffered Stderr Space)
12421         (write-buffered Stderr %eax)
12422       }
12423       (write-buffered Stderr Newline)
12424       (flush Stderr)
12425       (emit-indent Stderr *(ebp+8))
12426       (write-buffered Stderr "block depth: ")
12427       (write-int32-hex-buffered Stderr *(ebx+0x10))  # Var-block-depth
12428       (write-buffered Stderr Newline)
12429       (flush Stderr)
12430       (emit-indent Stderr *(ebp+8))
12431       (write-buffered Stderr "stack offset: ")
12432       (write-int32-hex-buffered Stderr *(ebx+0x14))  # Var-offset
12433       (write-buffered Stderr Newline)
12434       (flush Stderr)
12435       (emit-indent Stderr *(ebp+8))
12436       (write-buffered Stderr "reg: ")
12437       (write-int32-hex-buffered Stderr *(ebx+0x18))  # Var-register
12438       (write-buffered Stderr ",")
12439       (write-int32-hex-buffered Stderr *(ebx+0x1c))  # Var-register
12440       (write-buffered Stderr "->")
12441       (flush Stderr)
12442       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register
12443       (write-int32-hex-buffered Stderr %eax)
12444       {
12445         3d/compare-eax-and 0/imm32
12446         74/jump-if-= break/disp8
12447         (write-buffered Stderr Space)
12448         (write-buffered Stderr %eax)
12449       }
12450       (write-buffered Stderr Newline)
12451       (flush Stderr)
12452     }
12453 $dump-var:end:
12454     # . restore registers
12455     5b/pop-to-ebx
12456     58/pop-to-eax
12457     # . epilogue
12458     89/<- %esp 5/r32/ebp
12459     5d/pop-to-ebp
12460     c3/return
12461 
12462 #######################################################
12463 # Type-checking
12464 #######################################################
12465 
12466 check-mu-types:  # err: (addr buffered-file), ed: (addr exit-descriptor)
12467     # . prologue
12468     55/push-ebp
12469     89/<- %ebp 4/r32/esp
12470     # . save registers
12471     50/push-eax
12472     # var curr/eax: (addr function) = lookup(Program->functions)
12473     (lookup *_Program-functions *_Program-functions->payload)  # => eax
12474     {
12475 $check-mu-types:loop:
12476       # if (curr == null) break
12477       3d/compare-eax-and 0/imm32
12478       0f 84/jump-if-= break/disp32
12479 +--  8 lines: #?       # dump curr->name ------------------------------------------------------------------------------------------------------------------------------------------------
12487       (check-mu-function %eax *(ebp+8) *(ebp+0xc))
12488       # curr = lookup(curr->next)
12489       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
12490       e9/jump loop/disp32
12491     }
12492 $check-mu-types:end:
12493     # . restore registers
12494     58/pop-to-eax
12495     # . epilogue
12496     89/<- %esp 5/r32/ebp
12497     5d/pop-to-ebp
12498     c3/return
12499 
12500 check-mu-function:  # fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12501     # . prologue
12502     55/push-ebp
12503     89/<- %ebp 4/r32/esp
12504     # . save registers
12505     50/push-eax
12506     # eax = f
12507     8b/-> *(ebp+8) 0/r32/eax
12508     # TODO: anything to check in header?
12509     # var body/eax: (addr block) = lookup(f->body)
12510     (lookup *(eax+0x18) *(eax+0x1c))  # Function-body Function-body => eax
12511     (check-mu-block %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10))
12512 $check-mu-function:end:
12513     # . restore registers
12514     58/pop-to-eax
12515     # . epilogue
12516     89/<- %esp 5/r32/ebp
12517     5d/pop-to-ebp
12518     c3/return
12519 
12520 check-mu-block:  # block: (addr block), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12521     # . prologue
12522     55/push-ebp
12523     89/<- %ebp 4/r32/esp
12524     # . save registers
12525     50/push-eax
12526     # eax = block
12527     8b/-> *(ebp+8) 0/r32/eax
12528     # var stmts/eax: (addr list stmt) = lookup(block->statements)
12529     (lookup *(eax+4) *(eax+8))  # Block-stmts Block-stmts => eax
12530     #
12531     {
12532 $check-mu-block:check-empty:
12533       3d/compare-eax-and 0/imm32
12534       0f 84/jump-if-= break/disp32
12535       # emit block->statements
12536       (check-mu-stmt-list %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12537     }
12538 $check-mu-block:end:
12539     # . restore registers
12540     58/pop-to-eax
12541     # . epilogue
12542     89/<- %esp 5/r32/ebp
12543     5d/pop-to-ebp
12544     c3/return
12545 
12546 check-mu-stmt-list:  # stmts: (addr list stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12547     # . prologue
12548     55/push-ebp
12549     89/<- %ebp 4/r32/esp
12550     # . save registers
12551     50/push-eax
12552     56/push-esi
12553     # esi = stmts
12554     8b/-> *(ebp+8) 6/r32/esi
12555     {
12556 $check-mu-stmt-list:loop:
12557       81 7/subop/compare %esi 0/imm32
12558       0f 84/jump-if-= break/disp32
12559       # var curr-stmt/eax: (addr stmt) = lookup(stmts->value)
12560       (lookup *esi *(esi+4))  # List-value List-value => eax
12561       {
12562 $check-mu-stmt-list:check-for-block:
12563         81 7/subop/compare *eax 0/imm32/block  # Stmt-tag
12564         75/jump-if-!= break/disp8
12565 $check-mu-stmt-list:block:
12566         (check-mu-block %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12567         eb/jump $check-mu-stmt-list:continue/disp8
12568       }
12569       {
12570 $check-mu-stmt-list:check-for-stmt1:
12571         81 7/subop/compare *eax 1/imm32/stmt1  # Stmt-tag
12572         0f 85/jump-if-!= break/disp32
12573 $check-mu-stmt-list:stmt1:
12574         (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12575         eb/jump $check-mu-stmt-list:continue/disp8
12576       }
12577       {
12578 $check-mu-stmt-list:check-for-reg-var-def:
12579         81 7/subop/compare *eax 3/imm32/reg-var-def  # Stmt-tag
12580         0f 85/jump-if-!= break/disp32
12581 $check-mu-stmt-list:reg-var-def:
12582         (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12583         eb/jump $check-mu-stmt-list:continue/disp8
12584       }
12585 $check-mu-stmt-list:continue:
12586       # TODO: raise an error on unrecognized Stmt-tag
12587       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
12588       89/<- %esi 0/r32/eax
12589       e9/jump loop/disp32
12590     }
12591 $check-mu-stmt-list:end:
12592     # . restore registers
12593     5e/pop-to-esi
12594     58/pop-to-eax
12595     # . epilogue
12596     89/<- %esp 5/r32/ebp
12597     5d/pop-to-ebp
12598     c3/return
12599 
12600 check-mu-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12601     # . prologue
12602     55/push-ebp
12603     89/<- %ebp 4/r32/esp
12604     # . save registers
12605     50/push-eax
12606     # - if stmt's operation matches a primitive, check against it
12607     (has-primitive-name? *(ebp+8))  # => eax
12608     3d/compare-eax-and 0/imm32/false
12609     {
12610       74/jump-if-= break/disp8
12611       (check-mu-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12612       e9/jump $check-mu-stmt:end/disp32
12613     }
12614     # - otherwise find a function to check against
12615     # var f/eax: (addr function) = lookup(*Program->functions)
12616     (lookup *_Program-functions *_Program-functions->payload)  # => eax
12617     (find-matching-function %eax *(ebp+8))  # => eax
12618     3d/compare-eax-and 0/imm32
12619     {
12620       74/jump-if-= break/disp8
12621       (check-mu-call *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12622       eb/jump $check-mu-stmt:end/disp8
12623     }
12624     # var f/eax: (addr function) = lookup(*Program->signatures)
12625     (lookup *_Program-signatures *_Program-signatures->payload)  # => eax
12626     (find-matching-function %eax *(ebp+8))  # => eax
12627     3d/compare-eax-and 0/imm32
12628     {
12629       74/jump-if-= break/disp8
12630       (check-mu-call *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12631       eb/jump $check-mu-stmt:end/disp8
12632     }
12633     # - otherwise abort
12634     e9/jump $check-mu-stmt:unknown-call/disp32
12635 $check-mu-stmt:end:
12636     # . restore registers
12637     58/pop-to-eax
12638     # . epilogue
12639     89/<- %esp 5/r32/ebp
12640     5d/pop-to-ebp
12641     c3/return
12642 
12643 $check-mu-stmt:unknown-call:
12644     (write-buffered *(ebp+0x10) "unknown function '")
12645     8b/-> *(ebp+8) 0/r32/eax
12646     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
12647     (write-buffered *(ebp+0x10) %eax)
12648     (write-buffered *(ebp+0x10) "'\n")
12649     (flush *(ebp+0x10))
12650     (stop *(ebp+0x14) 1)
12651     # never gets here
12652 
12653 has-primitive-name?:  # stmt: (addr stmt) -> result/eax: boolean
12654     # . prologue
12655     55/push-ebp
12656     89/<- %ebp 4/r32/esp
12657     # . save registers
12658     51/push-ecx
12659     56/push-esi
12660     # var name/esi: (addr array byte) = lookup(stmt->operation)
12661     8b/-> *(ebp+8) 6/r32/esi
12662     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
12663     89/<- %esi 0/r32/eax
12664     # if (name == "get") return true
12665     (string-equal? %esi "get")  # => eax
12666     3d/compare-eax-and 0/imm32/false
12667     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12668     # if (name == "index") return true
12669     (string-equal? %esi "index")  # => eax
12670     3d/compare-eax-and 0/imm32/false
12671     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12672     # if (name == "length") return true
12673     (string-equal? %esi "length")  # => eax
12674     3d/compare-eax-and 0/imm32/false
12675     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12676     # if (name == "compute-offset") return true
12677     (string-equal? %esi "compute-offset")  # => eax
12678     3d/compare-eax-and 0/imm32/false
12679     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12680     # if (name == "allocate") return true
12681     (string-equal? %esi "allocate")  # => eax
12682     3d/compare-eax-and 0/imm32/false
12683     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12684     # if (name == "populate") return true
12685     (string-equal? %esi "populate")  # => eax
12686     3d/compare-eax-and 0/imm32/false
12687     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12688     # if (name == "populate-stream") return true
12689     (string-equal? %esi "populate-stream")  # => eax
12690     3d/compare-eax-and 0/imm32/false
12691     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12692     # if (name == "read-from-stream") return true
12693     (string-equal? %esi "read-from-stream")  # => eax
12694     3d/compare-eax-and 0/imm32/false
12695     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12696     # if (name == "write-to-stream") return true
12697     (string-equal? %esi "write-to-stream")  # => eax
12698     3d/compare-eax-and 0/imm32/false
12699     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12700     # var curr/ecx: (addr primitive) = Primitives
12701     b9/copy-to-ecx Primitives/imm32
12702     {
12703 $has-primitive-name?:loop:
12704       # if (curr == null) break
12705       81 7/subop/compare %ecx 0/imm32
12706       74/jump-if-= break/disp8
12707       # if (primitive->name == name) return true
12708       (lookup *ecx *(ecx+4))  # Primitive-name Primitive-name => eax
12709       (string-equal? %esi %eax)  # => eax
12710       3d/compare-eax-and 0/imm32/false
12711       75/jump-if-!= $has-primitive-name?:end/disp8
12712 $has-primitive-name?:next-primitive:
12713       # curr = curr->next
12714       (lookup *(ecx+0x38) *(ecx+0x3c))  # Primitive-next Primitive-next => eax
12715       89/<- %ecx 0/r32/eax
12716       #
12717       e9/jump loop/disp32
12718     }
12719     # return null
12720     b8/copy-to-eax 0/imm32
12721 $has-primitive-name?:end:
12722     # . restore registers
12723     5e/pop-to-esi
12724     59/pop-to-ecx
12725     # . epilogue
12726     89/<- %esp 5/r32/ebp
12727     5d/pop-to-ebp
12728     c3/return
12729 
12730 check-mu-primitive:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12731     # . prologue
12732     55/push-ebp
12733     89/<- %ebp 4/r32/esp
12734     # . save registers
12735     50/push-eax
12736     51/push-ecx
12737     # var op/ecx: (addr array byte) = lookup(stmt->operation)
12738     8b/-> *(ebp+8) 0/r32/eax
12739     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
12740     89/<- %ecx 0/r32/eax
12741     # if (op == "copy") check-mu-copy-stmt
12742     {
12743       (string-equal? %ecx "copy")  # => eax
12744       3d/compare-eax-and 0/imm32/false
12745       74/jump-if-= break/disp8
12746       (check-mu-copy-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12747       e9/jump $check-mu-primitive:end/disp32
12748     }
12749     # if (op == "copy-to") check-mu-copy-to-stmt
12750     {
12751       (string-equal? %ecx "copy-to")  # => eax
12752       3d/compare-eax-and 0/imm32/false
12753       74/jump-if-= break/disp8
12754       (check-mu-copy-to-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12755       e9/jump $check-mu-primitive:end/disp32
12756     }
12757     # if (op == "compare") check-mu-compare-stmt
12758     {
12759       (string-equal? %ecx "compare")  # => eax
12760       3d/compare-eax-and 0/imm32/false
12761       74/jump-if-= break/disp8
12762       (check-mu-compare-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12763       e9/jump $check-mu-primitive:end/disp32
12764     }
12765     # if (op == "address") check-mu-address-stmt
12766     {
12767       (string-equal? %ecx "address")  # => eax
12768       3d/compare-eax-and 0/imm32/false
12769       74/jump-if-= break/disp8
12770       (check-mu-address-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12771       e9/jump $check-mu-primitive:end/disp32
12772     }
12773     # if (op == "get") check-mu-get-stmt
12774     {
12775       (string-equal? %ecx "get")  # => eax
12776       3d/compare-eax-and 0/imm32/false
12777       74/jump-if-= break/disp8
12778       (check-mu-get-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12779       e9/jump $check-mu-primitive:end/disp32
12780     }
12781     # if (op == "index") check-mu-index-stmt
12782     {
12783       (string-equal? %ecx "index")  # => eax
12784       3d/compare-eax-and 0/imm32/false
12785       74/jump-if-= break/disp8
12786       (check-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12787       e9/jump $check-mu-primitive:end/disp32
12788     }
12789     # if (op == "length") check-mu-length-stmt
12790     {
12791       (string-equal? %ecx "length")  # => eax
12792       3d/compare-eax-and 0/imm32/false
12793       74/jump-if-= break/disp8
12794       (check-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12795       e9/jump $check-mu-primitive:end/disp32
12796     }
12797     # if (op == "compute-offset") check-mu-compute-offset-stmt
12798     {
12799       (string-equal? %ecx "compute-offset")  # => eax
12800       3d/compare-eax-and 0/imm32/false
12801       74/jump-if-= break/disp8
12802       (check-mu-compute-offset-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12803       e9/jump $check-mu-primitive:end/disp32
12804     }
12805     # if (op == "allocate") check-mu-allocate-stmt
12806     {
12807       (string-equal? %ecx "allocate")  # => eax
12808       3d/compare-eax-and 0/imm32/false
12809       74/jump-if-= break/disp8
12810       (check-mu-allocate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12811       e9/jump $check-mu-primitive:end/disp32
12812     }
12813     # if (op == "populate") check-mu-populate-stmt
12814     {
12815       (string-equal? %ecx "populate")  # => eax
12816       3d/compare-eax-and 0/imm32/false
12817       74/jump-if-= break/disp8
12818       (check-mu-populate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12819       e9/jump $check-mu-primitive:end/disp32
12820     }
12821     # if (op == "populate-stream") check-mu-populate-stream-stmt
12822     {
12823       (string-equal? %ecx "populate-stream")  # => eax
12824       3d/compare-eax-and 0/imm32/false
12825       74/jump-if-= break/disp8
12826       (check-mu-populate-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12827       e9/jump $check-mu-primitive:end/disp32
12828     }
12829     # if (op == "read-from-stream") check-mu-read-from-stream-stmt
12830     {
12831       (string-equal? %ecx "read-from-stream")  # => eax
12832       3d/compare-eax-and 0/imm32/false
12833       74/jump-if-= break/disp8
12834       (check-mu-read-from-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12835       e9/jump $check-mu-primitive:end/disp32
12836     }
12837     # if (op == "write-to-stream") check-mu-write-to-stream-stmt
12838     {
12839       (string-equal? %ecx "write-to-stream")  # => eax
12840       3d/compare-eax-and 0/imm32/false
12841       74/jump-if-= break/disp8
12842       (check-mu-write-to-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12843       e9/jump $check-mu-primitive:end/disp32
12844     }
12845     # otherwise check-numberlike-stmt
12846     (check-mu-numberlike-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12847 $check-mu-primitive:end:
12848     # . restore registers
12849     59/pop-to-ecx
12850     58/pop-to-eax
12851     # . epilogue
12852     89/<- %esp 5/r32/ebp
12853     5d/pop-to-ebp
12854     c3/return
12855 
12856 # by default, Mu primitives should only operate on 'number-like' types
12857 check-mu-numberlike-primitive:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12858     # . prologue
12859     55/push-ebp
12860     89/<- %ebp 4/r32/esp
12861     # . save registers
12862     50/push-eax
12863     51/push-ecx
12864     56/push-esi
12865     # esi = stmt
12866     8b/-> *(ebp+8) 6/r32/esi
12867     # var gas/ecx: int = 2
12868     b9/copy-to-ecx 2/imm32
12869     # - check at most 1 output
12870     # var output/eax: (addr stmt-var) = stmt->outputs
12871     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
12872     {
12873       3d/compare-eax-and 0/imm32
12874       74/jump-if-= break/disp8
12875 $check-mu-numberlike-primitive:output:
12876       (check-mu-numberlike-output %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12877       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
12878       3d/compare-eax-and 0/imm32
12879       0f 85/jump-if-!= $check-mu-numberlike-primitive:error-too-many-outputs/disp32
12880       # check output is in a register
12881       # --gas
12882       49/decrement-ecx
12883     }
12884     # - check first inout
12885     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12886     {
12887       3d/compare-eax-and 0/imm32
12888       0f 84/jump-if-= $check-mu-numberlike-primitive:end/disp32
12889 $check-mu-numberlike-primitive:first-inout:
12890       (check-mu-numberlike-arg %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12891       # --gas
12892       49/decrement-ecx
12893     }
12894     # - check second inout
12895     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
12896     {
12897       3d/compare-eax-and 0/imm32
12898       74/jump-if-= $check-mu-numberlike-primitive:end/disp8
12899 $check-mu-numberlike-primitive:second-inout:
12900       # is a second inout allowed?
12901       81 7/subop/compare %ecx 0/imm32
12902       0f 84/jump-if-= $check-mu-numberlike-primitive:error-too-many-inouts/disp32
12903 $check-mu-numberlike-primitive:second-inout-permitted:
12904       (check-mu-numberlike-arg %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12905     }
12906 $check-mu-numberlike-primitive:third-inout:
12907     # if there's a third arg, raise an error
12908     81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
12909     0f 85/jump-if-!= $check-mu-numberlike-primitive:error-too-many-inouts/disp32
12910 $check-mu-numberlike-primitive:end:
12911     # . restore registers
12912     5e/pop-to-esi
12913     59/pop-to-ecx
12914     58/pop-to-eax
12915     # . epilogue
12916     89/<- %esp 5/r32/ebp
12917     5d/pop-to-ebp
12918     c3/return
12919 
12920 $check-mu-numberlike-primitive:error-too-many-inouts:
12921     (write-buffered *(ebp+0x10) "fn ")
12922     8b/-> *(ebp+0xc) 0/r32/eax
12923     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12924     (write-buffered *(ebp+0x10) %eax)
12925     (write-buffered *(ebp+0x10) ": stmt ")
12926     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
12927     (write-buffered *(ebp+0x10) %eax)
12928     (write-buffered *(ebp+0x10) ": too many inouts; most primitives support at most two arguments, across inouts and outputs\n")
12929     (flush *(ebp+0x10))
12930     (stop *(ebp+0x14) 1)
12931     # never gets here
12932 
12933 $check-mu-numberlike-primitive:error-too-many-outputs:
12934     (write-buffered *(ebp+0x10) "fn ")
12935     8b/-> *(ebp+0xc) 0/r32/eax
12936     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12937     (write-buffered *(ebp+0x10) %eax)
12938     (write-buffered *(ebp+0x10) ": stmt ")
12939     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
12940     (write-buffered *(ebp+0x10) %eax)
12941     (write-buffered *(ebp+0x10) ": too many outputs; most primitives support at most one output\n")
12942     (flush *(ebp+0x10))
12943     (stop *(ebp+0x14) 1)
12944     # never gets here
12945 
12946 check-mu-numberlike-arg:  # v: (addr stmt-var), stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12947     # . prologue
12948     55/push-ebp
12949     89/<- %ebp 4/r32/esp
12950     # . save registers
12951     50/push-eax
12952     56/push-esi
12953     # var t/esi: (addr type-tree) = lookup(v->value->type)
12954     8b/-> *(ebp+8) 0/r32/eax
12955     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12956     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12957     89/<- %esi 0/r32/eax
12958 $check-mu-numberlike-arg:check-literal:
12959     # if t is an int, return
12960     (is-simple-mu-type? %esi 0)  # literal => eax
12961     3d/compare-eax-and 0/imm32/false
12962     75/jump-if-!= $check-mu-numberlike-arg:end/disp8
12963 $check-mu-numberlike-arg:check-addr:
12964     # if t is an addr and v is dereferenced, return
12965     {
12966       (is-mu-addr-type? %esi)  # => eax
12967       3d/compare-eax-and 0/imm32/false
12968       74/jump-if-= break/disp8
12969       8b/-> *(ebp+8) 0/r32/eax
12970       8b/-> *(eax+0x10) 0/r32/eax
12971       3d/compare-eax-and 0/imm32/false
12972       75/jump-if-!= $check-mu-numberlike-arg:end/disp8
12973     }
12974 $check-mu-numberlike-arg:output-checks:
12975     (check-mu-numberlike-output *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18))
12976 $check-mu-numberlike-arg:end:
12977     # . restore registers
12978     5e/pop-to-esi
12979     58/pop-to-eax
12980     # . epilogue
12981     89/<- %esp 5/r32/ebp
12982     5d/pop-to-ebp
12983     c3/return
12984 
12985 check-mu-numberlike-output:  # v: (addr stmt-var), stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12986     # . prologue
12987     55/push-ebp
12988     89/<- %ebp 4/r32/esp
12989     # . save registers
12990     50/push-eax
12991     56/push-esi
12992     # var t/esi: (addr type-tree) = lookup(v->value->type)
12993     8b/-> *(ebp+8) 0/r32/eax
12994     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12995     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12996     89/<- %esi 0/r32/eax
12997 $check-mu-numberlike-output:check-int:
12998     # if t is an int, return
12999     (is-simple-mu-type? %esi 1)  # int => eax
13000     3d/compare-eax-and 0/imm32/false
13001     75/jump-if-!= $check-mu-numberlike-output:end/disp8
13002 $check-mu-numberlike-output:check-boolean:
13003     # if t is a boolean, return
13004     (is-simple-mu-type? %esi 5)  # boolean => eax
13005     3d/compare-eax-and 0/imm32/false
13006     75/jump-if-!= $check-mu-numberlike-output:end/disp8
13007 $check-mu-numberlike-output:check-byte:
13008     # if t is a byte, return
13009     (is-simple-mu-type? %esi 8)  # byte => eax
13010     3d/compare-eax-and 0/imm32/false
13011     75/jump-if-!= $check-mu-numberlike-output:end/disp8
13012     e9/jump $check-mu-numberlike-output:fail/disp32
13013 $check-mu-numberlike-output:end:
13014     # . restore registers
13015     5e/pop-to-esi
13016     58/pop-to-eax
13017     # . epilogue
13018     89/<- %esp 5/r32/ebp
13019     5d/pop-to-ebp
13020     c3/return
13021 
13022 $check-mu-numberlike-output:fail:
13023     # otherwise raise an error
13024     (write-buffered *(ebp+0x14) "fn ")
13025     8b/-> *(ebp+0x10) 0/r32/eax
13026     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13027     (write-buffered *(ebp+0x14) %eax)
13028     (write-buffered *(ebp+0x14) ": stmt ")
13029     8b/-> *(ebp+0xc) 0/r32/eax
13030     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
13031     (write-buffered *(ebp+0x14) %eax)
13032     (write-buffered *(ebp+0x14) ": only non-addr scalar args permitted\n")
13033     (flush *(ebp+0x14))
13034     (stop *(ebp+0x18) 1)
13035     # never gets here
13036 
13037 check-mu-copy-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13038     # . prologue
13039     55/push-ebp
13040     89/<- %ebp 4/r32/esp
13041     # . save registers
13042 $check-mu-copy-stmt:end:
13043     # . restore registers
13044     # . epilogue
13045     89/<- %esp 5/r32/ebp
13046     5d/pop-to-ebp
13047     c3/return
13048 
13049 check-mu-copy-to-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13050     # . prologue
13051     55/push-ebp
13052     89/<- %ebp 4/r32/esp
13053     # . save registers
13054 $check-mu-copy-to-stmt:end:
13055     # . restore registers
13056     # . epilogue
13057     89/<- %esp 5/r32/ebp
13058     5d/pop-to-ebp
13059     c3/return
13060 
13061 check-mu-compare-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13062     # . prologue
13063     55/push-ebp
13064     89/<- %ebp 4/r32/esp
13065     # . save registers
13066 $check-mu-compare-stmt:end:
13067     # . restore registers
13068     # . epilogue
13069     89/<- %esp 5/r32/ebp
13070     5d/pop-to-ebp
13071     c3/return
13072 
13073 check-mu-address-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13074     # . prologue
13075     55/push-ebp
13076     89/<- %ebp 4/r32/esp
13077     # . save registers
13078 $check-mu-address-stmt:end:
13079     # . restore registers
13080     # . epilogue
13081     89/<- %esp 5/r32/ebp
13082     5d/pop-to-ebp
13083     c3/return
13084 
13085 check-mu-get-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13086     # . prologue
13087     55/push-ebp
13088     89/<- %ebp 4/r32/esp
13089     # . save registers
13090     50/push-eax
13091     51/push-ecx
13092     52/push-edx
13093     53/push-ebx
13094     56/push-esi
13095     57/push-edi
13096     # esi = stmt
13097     8b/-> *(ebp+8) 6/r32/esi
13098     # - check for 0 inouts
13099     # var base/ecx: (addr var) = stmt->inouts->value
13100     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13101     3d/compare-eax-and 0/imm32/false
13102     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-inouts/disp32
13103     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13104     89/<- %ecx 0/r32/eax
13105 $check-mu-get-stmt:check-base:
13106     # - check base type
13107     # if it's an 'addr', check that it's in a register
13108     # var base-type/ebx: (addr type-tree) = lookup(base->type)
13109     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
13110     89/<- %ebx 0/r32/eax
13111     {
13112       81 7/subop/compare *ebx 0/imm32/false  # Type-tree-is-atom
13113       0f 85/jump-if-!= break/disp32
13114 $check-mu-get-stmt:base-is-compound:
13115       # if (type->left != addr) break
13116       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
13117       (is-simple-mu-type? %eax 2)  # addr => eax
13118       3d/compare-eax-and 0/imm32/false
13119       74/jump-if-= break/disp8
13120 $check-mu-get-stmt:base-is-addr:
13121       # now check for register
13122       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
13123       0f 84/jump-if-= $check-mu-get-stmt:error-base-type-addr-but-not-register/disp32
13124 $check-mu-get-stmt:base-is-addr-in-register:
13125       # type->left is now an addr; skip it
13126       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
13127       81 7/subop/compare *(eax+0xc) 0/imm32  # Type-tree-right
13128       0f 85/jump-if-!= $check-mu-get-stmt:error-bad-base/disp32
13129 $check-mu-get-stmt:base-is-addr-to-atom-in-register:
13130       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
13131       89/<- %ebx 0/r32/eax
13132     }
13133 $check-mu-get-stmt:check-base-typeinfo:
13134     # ensure type is a container
13135     # var base-type-id/ebx: type-id = base-type->value
13136     8b/-> *(ebx+4) 3/r32/ebx  # Type-tree-value
13137     (is-container? %ebx)  # => eax
13138     3d/compare-eax-and 0/imm32/false
13139     0f 84/jump-if-= $check-mu-get-stmt:error-bad-base/disp32
13140     # var base-typeinfo/edx: (addr typeinfo) = find-typeinfo(base-type-id)
13141     # . var container/ecx: (handle typeinfo)
13142     68/push 0/imm32
13143     68/push 0/imm32
13144     89/<- %ecx 4/r32/esp
13145     # .
13146     (find-typeinfo %ebx %ecx)
13147     (lookup *ecx *(ecx+4))  # => eax
13148     # . reclaim container
13149     81 0/subop/add %esp 8/imm32
13150     # .
13151     89/<- %edx 0/r32/eax
13152     # var offset/ecx: (addr stmt-var) = stmt->inouts->next
13153     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13154     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13155     89/<- %ecx 0/r32/eax
13156     # - check for 1 inout
13157     3d/compare-eax-and 0/imm32/false
13158     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-inouts/disp32
13159     # var offset/ecx: (addr var) = lookup(offset->value)
13160     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
13161     89/<- %ecx 0/r32/eax
13162     # - check for valid field
13163     81 7/subop/compare *(ecx+0x14) -1/imm32/uninitialized  # Var-offset
13164     0f 84/jump-if-= $check-mu-get-stmt:error-bad-field/disp32
13165     # - check for too many inouts
13166     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13167     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13168     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13169     3d/compare-eax-and 0/imm32/false
13170     0f 85/jump-if-!= $check-mu-get-stmt:error-too-many-inouts/disp32
13171     # var output/edi: (addr var) = stmt->outputs->value
13172     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13173     # - check for 0 outputs
13174     3d/compare-eax-and 0/imm32/false
13175     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-outputs/disp32
13176     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13177     89/<- %edi 0/r32/eax
13178 $check-mu-get-stmt:check-output-type:
13179     # - check output type
13180     # must be in register
13181     (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
13182     3d/compare-eax-and 0/imm32
13183     0f 84/jump-if-= $check-mu-get-stmt:error-output-not-in-register/disp32
13184     # must have a non-atomic type
13185     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
13186     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
13187     0f 85/jump-if-!= $check-mu-get-stmt:error-output-type-not-address/disp32
13188     # type must start with (addr ...)
13189     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
13190     (is-simple-mu-type? %eax 2)  # => eax
13191     3d/compare-eax-and 0/imm32/false
13192     0f 84/jump-if-= $check-mu-get-stmt:error-output-type-not-address/disp32
13193 $check-mu-get-stmt:check-output-type-match:
13194     # payload of addr type must match 'type' definition
13195     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
13196     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
13197     # if (payload->right == null) payload = payload->left
13198     81 7/subop/compare *(eax+0xc) 0/imm32/null  # Type-tree-right
13199     {
13200       75/jump-if-!= break/disp8
13201       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
13202     }
13203     89/<- %edi 0/r32/eax
13204     # . var output-name/ecx: (addr array byte)
13205     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13206     89/<- %ecx 0/r32/eax
13207     # . var base-typeinfo-entry/eax: (addr handle typeinfo-entry)
13208     (lookup *(edx+4) *(edx+8))  # Typeinfo-fields Typeinfo-fields => eax
13209     (get %eax %ecx 0x10)  # => eax
13210     # .
13211     (lookup *eax *(eax+4))  # => eax
13212     (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
13213     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
13214     # .
13215     (type-equal? %edi %eax)  # => eax
13216     3d/compare-eax-and 0/imm32/false
13217     0f 84/jump-if-= $check-mu-get-stmt:error-bad-output-type/disp32
13218     # - check for too many outputs
13219     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13220     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13221     3d/compare-eax-and 0/imm32/false
13222     0f 85/jump-if-!= $check-mu-get-stmt:error-too-many-outputs/disp32
13223 $check-mu-get-stmt:end:
13224     # . restore registers
13225     5f/pop-to-edi
13226     5e/pop-to-esi
13227     5b/pop-to-ebx
13228     5a/pop-to-edx
13229     59/pop-to-ecx
13230     58/pop-to-eax
13231     # . epilogue
13232     89/<- %esp 5/r32/ebp
13233     5d/pop-to-ebp
13234     c3/return
13235 
13236 $check-mu-get-stmt:error-too-few-inouts:
13237     (write-buffered *(ebp+0x10) "fn ")
13238     8b/-> *(ebp+0xc) 0/r32/eax
13239     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13240     (write-buffered *(ebp+0x10) %eax)
13241     (write-buffered *(ebp+0x10) ": stmt get: too few inouts (2 required)\n")
13242     (flush *(ebp+0x10))
13243     (stop *(ebp+0x14) 1)
13244     # never gets here
13245 
13246 $check-mu-get-stmt:error-too-many-inouts:
13247     (write-buffered *(ebp+0x10) "fn ")
13248     8b/-> *(ebp+0xc) 0/r32/eax
13249     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13250     (write-buffered *(ebp+0x10) %eax)
13251     (write-buffered *(ebp+0x10) ": stmt get: too many inouts (2 required)\n")
13252     (flush *(ebp+0x10))
13253     (stop *(ebp+0x14) 1)
13254     # never gets here
13255 
13256 $check-mu-get-stmt:error-too-few-outputs:
13257     (write-buffered *(ebp+0x10) "fn ")
13258     8b/-> *(ebp+0xc) 0/r32/eax
13259     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13260     (write-buffered *(ebp+0x10) %eax)
13261     (write-buffered *(ebp+0x10) ": stmt get: must have an output\n")
13262     (flush *(ebp+0x10))
13263     (stop *(ebp+0x14) 1)
13264     # never gets here
13265 
13266 $check-mu-get-stmt:error-too-many-outputs:
13267     (write-buffered *(ebp+0x10) "fn ")
13268     8b/-> *(ebp+0xc) 0/r32/eax
13269     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13270     (write-buffered *(ebp+0x10) %eax)
13271     (write-buffered *(ebp+0x10) ": stmt get: too many outputs (1 required)\n")
13272     (flush *(ebp+0x10))
13273     (stop *(ebp+0x14) 1)
13274     # never gets here
13275 
13276 $check-mu-get-stmt:error-bad-base:
13277     # error("fn " fn ": stmt get: var '" base->name "' must have a 'type' definition\n")
13278     (write-buffered *(ebp+0x10) "fn ")
13279     8b/-> *(ebp+0xc) 0/r32/eax
13280     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13281     (write-buffered *(ebp+0x10) %eax)
13282     (write-buffered *(ebp+0x10) ": stmt get: var '")
13283     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13284     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13285     (lookup *eax *(eax+4))  # Var-name Var-name => eax
13286     (write-buffered *(ebp+0x10) %eax)
13287     (write-buffered *(ebp+0x10) "' must have a 'type' definition\n")
13288     (flush *(ebp+0x10))
13289     (stop *(ebp+0x14) 1)
13290     # never gets here
13291 
13292 $check-mu-get-stmt:error-base-type-addr-but-not-register:
13293     (write-buffered *(ebp+0x10) "fn ")
13294     8b/-> *(ebp+0xc) 0/r32/eax
13295     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13296     (write-buffered *(ebp+0x10) %eax)
13297     (write-buffered *(ebp+0x10) ": stmt get: var '")
13298     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13299     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13300     (lookup *eax *(eax+4))  # Var-name Var-name => eax
13301     (write-buffered *(ebp+0x10) %eax)
13302     (write-buffered *(ebp+0x10) "' is an 'addr' type, and so must live in a register\n")
13303     (flush *(ebp+0x10))
13304     (stop *(ebp+0x14) 1)
13305     # never gets here
13306 
13307 $check-mu-get-stmt:error-bad-field:
13308     # error("fn " fn ": stmt get: type " type " has no member called '" curr->name "'\n")
13309     (write-buffered *(ebp+0x10) "fn ")
13310     8b/-> *(ebp+0xc) 0/r32/eax
13311     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13312     (write-buffered *(ebp+0x10) %eax)
13313     (write-buffered *(ebp+0x10) ": stmt get: type '")
13314     # . write(Type-id->data[tmp])
13315     bf/copy-to-edi Type-id/imm32
13316     (write-buffered *(ebp+0x10) *(edi+ebx<<2+0xc))
13317     # .
13318     (write-buffered *(ebp+0x10) "' has no member called '")
13319     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13320     (write-buffered *(ebp+0x10) %eax)
13321     (write-buffered *(ebp+0x10) "'\n")
13322     (flush *(ebp+0x10))
13323     (stop *(ebp+0x14) 1)
13324     # never gets here
13325 
13326 $check-mu-get-stmt:error-output-not-in-register:
13327     (write-buffered *(ebp+0x10) "fn ")
13328     8b/-> *(ebp+0xc) 0/r32/eax
13329     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13330     (write-buffered *(ebp+0x10) %eax)
13331     (write-buffered *(ebp+0x10) ": stmt get: output '")
13332     (lookup *edi *(edi+4))  # Var-name Var-name => eax
13333     (write-buffered *(ebp+0x10) %eax)
13334     (write-buffered *(ebp+0x10) "' is not in a register\n")
13335     (flush *(ebp+0x10))
13336     (stop *(ebp+0x14) 1)
13337     # never gets here
13338 
13339 $check-mu-get-stmt:error-output-type-not-address:
13340     (write-buffered *(ebp+0x10) "fn ")
13341     8b/-> *(ebp+0xc) 0/r32/eax
13342     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13343     (write-buffered *(ebp+0x10) %eax)
13344     (write-buffered *(ebp+0x10) ": stmt get: output must be an address\n")
13345     (flush *(ebp+0x10))
13346     (stop *(ebp+0x14) 1)
13347     # never gets here
13348 
13349 $check-mu-get-stmt:error-bad-output-type:
13350     (write-buffered *(ebp+0x10) "fn ")
13351     8b/-> *(ebp+0xc) 0/r32/eax
13352     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13353     (write-buffered *(ebp+0x10) %eax)
13354     (write-buffered *(ebp+0x10) ": stmt get: wrong output type for member '")
13355     (write-buffered *(ebp+0x10) %ecx)
13356     (write-buffered *(ebp+0x10) "' of type '")
13357     bf/copy-to-edi Type-id/imm32
13358     (write-buffered *(ebp+0x10) *(edi+ebx<<2+0xc))
13359     (write-buffered *(ebp+0x10) "'\n")
13360     (flush *(ebp+0x10))
13361     (stop *(ebp+0x14) 1)
13362     # never gets here
13363 
13364 check-mu-index-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13365     # . prologue
13366     55/push-ebp
13367     89/<- %ebp 4/r32/esp
13368     # . save registers
13369     50/push-eax
13370     51/push-ecx
13371     52/push-edx
13372     53/push-ebx
13373     56/push-esi
13374     57/push-edi
13375     # esi = stmt
13376     8b/-> *(ebp+8) 6/r32/esi
13377     # - check for 0 inouts
13378     # var base/ecx: (addr var) = stmt->inouts->value
13379     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13380 $check-mu-index-stmt:check-no-inouts:
13381     3d/compare-eax-and 0/imm32
13382     0f 84/jump-if-= $check-mu-index-stmt:error-too-few-inouts/disp32
13383     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13384     89/<- %ecx 0/r32/eax
13385     # - check base type is either (addr array ...) in register or (array ...) on stack
13386     # var base-type/ebx: (addr type-tree) = lookup(base->type)
13387     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
13388     89/<- %ebx 0/r32/eax
13389     # if base-type is an atom, abort with a precise error
13390     81 7/subop/compare *ebx 0/imm32/false  # Type-tree-is-atom
13391     {
13392       74/jump-if-= break/disp8
13393       (is-simple-mu-type? %ebx 3)  # array => eax
13394       3d/compare-eax-and 0/imm32/false
13395       0f 85/jump-if-!= $check-mu-index-stmt:error-base-array-atom-type/disp32
13396       0f 84/jump-if-= $check-mu-index-stmt:error-base-non-array-type/disp32
13397     }
13398 $check-mu-index-stmt:base-is-compound:
13399     # if type->left not addr or array, abort
13400     {
13401       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
13402       (is-simple-mu-type? %eax 2)  # addr => eax
13403       3d/compare-eax-and 0/imm32/false
13404       75/jump-if-!= break/disp8
13405       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
13406       (is-simple-mu-type? %eax 3)  # array => eax
13407       3d/compare-eax-and 0/imm32/false
13408       75/jump-if-!= break/disp8
13409       e9/jump $check-mu-index-stmt:error-base-non-array-type/disp32
13410     }
13411     # if (type->left == addr) ensure type->right->left == array and type->register exists
13412     {
13413       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
13414       (is-simple-mu-type? %eax 2)  # addr => eax
13415       3d/compare-eax-and 0/imm32/false
13416       74/jump-if-= break/disp8
13417 $check-mu-index-stmt:base-is-addr:
13418       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
13419       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
13420       (is-simple-mu-type? %eax 3)  # array => eax
13421       3d/compare-eax-and 0/imm32/false
13422       0f 84/jump-if-= $check-mu-index-stmt:error-base-non-array-type/disp32
13423 $check-mu-index-stmt:check-base-addr-is-register:
13424       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
13425       0f 84/jump-if-= $check-mu-index-stmt:error-base-address-array-type-on-stack/disp32
13426     }
13427     # if (type->left == array) ensure type->register doesn't exist
13428     {
13429       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
13430       (is-simple-mu-type? %eax 3)  # array => eax
13431       3d/compare-eax-and 0/imm32/false
13432       74/jump-if-= break/disp8
13433 $check-mu-index-stmt:base-is-array:
13434       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
13435       0f 85/jump-if-!= $check-mu-index-stmt:error-base-array-type-in-register/disp32
13436     }
13437     # if (base-type->left == addr) base-type = base-type->right
13438     {
13439       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
13440       (is-simple-mu-type? %eax 2)  # addr => eax
13441       3d/compare-eax-and 0/imm32/false
13442       74/jump-if-= break/disp8
13443       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
13444       89/<- %ebx 0/r32/eax
13445     }
13446     # - check for 1 inout
13447     # var index/ecx: (addr stmt-var) = stmt->inouts->next->value
13448     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13449     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13450 $check-mu-index-stmt:check-single-inout:
13451     3d/compare-eax-and 0/imm32
13452     0f 84/jump-if-= $check-mu-index-stmt:error-too-few-inouts/disp32
13453     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13454     89/<- %ecx 0/r32/eax
13455     # - check index is either a literal or register
13456     # var index-type/edx: (addr type-tree)
13457     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
13458     89/<- %edx 0/r32/eax
13459     # if index type is an atom, it must be a literal or int
13460     81 7/subop/compare *edx 0/imm32/false  # Type-tree-is-atom
13461     {
13462       74/jump-if-= break/disp8
13463 $check-mu-index-stmt:index-type-is-atom:
13464       (is-simple-mu-type? %edx 0)  # literal => eax
13465       3d/compare-eax-and 0/imm32/false
13466       75/jump-if-!= $check-mu-index-stmt:index-type-done/disp8
13467       (is-simple-mu-type? %edx 1)  # int => eax
13468       3d/compare-eax-and 0/imm32/false
13469       75/jump-if-!= $check-mu-index-stmt:index-type-done/disp8
13470       (is-simple-mu-type? %edx 7)  # offset => eax
13471       3d/compare-eax-and 0/imm32/false
13472       0f 85/jump-if-!= $check-mu-index-stmt:error-index-offset-atom-type/disp32
13473       e9/jump $check-mu-index-stmt:error-invalid-index-type/disp32
13474     }
13475     # if index type is a non-atom: it must be an offset
13476     {
13477       75/jump-if-!= break/disp8
13478 $check-mu-index-stmt:index-type-is-non-atom:
13479       (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
13480       (is-simple-mu-type? %eax 7)  # offset => eax
13481       3d/compare-eax-and 0/imm32/false
13482       0f 84/jump-if-= $check-mu-index-stmt:error-invalid-index-type/disp32
13483     }
13484 $check-mu-index-stmt:index-type-done:
13485     # check index is either a literal or in a register
13486     {
13487       (is-simple-mu-type? %edx 0)  # literal => eax
13488       3d/compare-eax-and 0/imm32/false
13489       75/jump-if-!= break/disp8
13490 $check-mu-index-stmt:check-index-in-register:
13491       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
13492       0f 84/jump-if-= $check-mu-index-stmt:error-index-on-stack/disp32
13493     }
13494     # - if index is an 'int', check that element type of base has size 1, 2, 4 or 8 bytes.
13495     {
13496       (is-simple-mu-type? %edx 1)  # int => eax
13497       3d/compare-eax-and 0/imm32/false
13498       74/jump-if-= break/disp8
13499 $check-mu-index-stmt:check-index-can-be-int:
13500       (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13501       (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13502       (array-element-size %eax)  # => eax
13503       3d/compare-eax-and 1/imm32
13504       74/jump-if-= break/disp8
13505       3d/compare-eax-and 2/imm32
13506       74/jump-if-= break/disp8
13507       3d/compare-eax-and 4/imm32
13508       74/jump-if-= break/disp8
13509       3d/compare-eax-and 8/imm32
13510       74/jump-if-= break/disp8
13511       e9/jump $check-mu-index-stmt:error-index-needs-offset/disp32
13512     }
13513     # - check for too many inouts
13514     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13515     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13516     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13517     3d/compare-eax-and 0/imm32/false
13518     0f 85/jump-if-!= $check-mu-index-stmt:error-too-many-inouts/disp32
13519     # - check for 0 outputs
13520     # var output/edi: (addr var) = stmt->outputs->value
13521     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13522     3d/compare-eax-and 0/imm32/false
13523     0f 84/jump-if-= $check-mu-index-stmt:error-too-few-outputs/disp32
13524     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13525     89/<- %edi 0/r32/eax
13526     # - check output type
13527     # must have a non-atomic type
13528     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
13529     89/<- %edx 0/r32/eax
13530     81 7/subop/compare *edx 0/imm32/false  # Type-tree-is-atom
13531     0f 85/jump-if-!= $check-mu-index-stmt:error-output-type-not-address/disp32
13532     # type must start with (addr ...)
13533     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
13534     (is-simple-mu-type? %eax 2)  # addr => eax
13535     3d/compare-eax-and 0/imm32/false
13536     0f 84/jump-if-= $check-mu-index-stmt:error-output-type-not-address/disp32
13537     # if tail(base-type) != tail(output-type) abort
13538     (type-tail %ebx)  # => eax
13539     89/<- %ebx 0/r32/eax
13540     (type-tail %edx)  # => eax
13541     (type-equal? %ebx %eax)  # => eax
13542     3d/compare-eax-and 0/imm32/false
13543     0f 84/jump-if-= $check-mu-index-stmt:error-bad-output-type/disp32
13544     # - check for too many outputs
13545     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13546     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13547     3d/compare-eax-and 0/imm32/false
13548     0f 85/jump-if-!= $check-mu-index-stmt:error-too-many-outputs/disp32
13549 $check-mu-index-stmt:end:
13550     # . restore registers
13551     5f/pop-to-edi
13552     5e/pop-to-esi
13553     5b/pop-to-ebx
13554     5a/pop-to-edx
13555     59/pop-to-ecx
13556     58/pop-to-eax
13557     # . epilogue
13558     89/<- %esp 5/r32/ebp
13559     5d/pop-to-ebp
13560     c3/return
13561 
13562 $check-mu-index-stmt:error-base-non-array-type:
13563     (write-buffered *(ebp+0x10) "fn ")
13564     8b/-> *(ebp+0xc) 0/r32/eax
13565     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13566     (write-buffered *(ebp+0x10) %eax)
13567     (write-buffered *(ebp+0x10) ": stmt index: var '")
13568     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13569     (write-buffered *(ebp+0x10) %eax)
13570     (write-buffered *(ebp+0x10) "' is not an array\n")
13571     (flush *(ebp+0x10))
13572     (stop *(ebp+0x14) 1)
13573     # never gets here
13574 
13575 $check-mu-index-stmt:error-base-array-atom-type:
13576     (write-buffered *(ebp+0x10) "fn ")
13577     8b/-> *(ebp+0xc) 0/r32/eax
13578     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13579     (write-buffered *(ebp+0x10) %eax)
13580     (write-buffered *(ebp+0x10) ": stmt index: array '")
13581     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13582     (write-buffered *(ebp+0x10) %eax)
13583     (write-buffered *(ebp+0x10) "' must specify the type of its elements\n")
13584     (flush *(ebp+0x10))
13585     (stop *(ebp+0x14) 1)
13586     # never gets here
13587 
13588 $check-mu-index-stmt:error-base-address-array-type-on-stack:
13589     (write-buffered *(ebp+0x10) "fn ")
13590     8b/-> *(ebp+0xc) 0/r32/eax
13591     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13592     (write-buffered *(ebp+0x10) %eax)
13593     (write-buffered *(ebp+0x10) ": stmt index: var '")
13594     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13595     (write-buffered *(ebp+0x10) %eax)
13596     (write-buffered *(ebp+0x10) "' is an addr to an array, and so must live in a register\n")
13597     (flush *(ebp+0x10))
13598     (stop *(ebp+0x14) 1)
13599     # never gets here
13600 
13601 $check-mu-index-stmt:error-base-array-type-in-register:
13602     (write-buffered *(ebp+0x10) "fn ")
13603     8b/-> *(ebp+0xc) 0/r32/eax
13604     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13605     (write-buffered *(ebp+0x10) %eax)
13606     (write-buffered *(ebp+0x10) ": stmt index: var '")
13607     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13608     (write-buffered *(ebp+0x10) %eax)
13609     (write-buffered *(ebp+0x10) "' is an array, and so must live on the stack\n")
13610     (flush *(ebp+0x10))
13611     (stop *(ebp+0x14) 1)
13612     # never gets here
13613 
13614 $check-mu-index-stmt:error-too-few-inouts:
13615     (write-buffered *(ebp+0x10) "fn ")
13616     8b/-> *(ebp+0xc) 0/r32/eax
13617     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13618     (write-buffered *(ebp+0x10) %eax)
13619     (write-buffered *(ebp+0x10) ": stmt index: too few inouts (2 required)\n")
13620     (flush *(ebp+0x10))
13621     (stop *(ebp+0x14) 1)
13622     # never gets here
13623 
13624 $check-mu-index-stmt:error-invalid-index-type:
13625     (write-buffered *(ebp+0x10) "fn ")
13626     8b/-> *(ebp+0xc) 0/r32/eax
13627     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13628     (write-buffered *(ebp+0x10) %eax)
13629     (write-buffered *(ebp+0x10) ": stmt index: second argument '")
13630     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13631     (write-buffered *(ebp+0x10) %eax)
13632     (write-buffered *(ebp+0x10) "' must be an int or offset\n")
13633     (flush *(ebp+0x10))
13634     (stop *(ebp+0x14) 1)
13635     # never gets here
13636 
13637 $check-mu-index-stmt:error-index-offset-atom-type:
13638     (write-buffered *(ebp+0x10) "fn ")
13639     8b/-> *(ebp+0xc) 0/r32/eax
13640     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13641     (write-buffered *(ebp+0x10) %eax)
13642     (write-buffered *(ebp+0x10) ": stmt index: offset '")
13643     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13644     (write-buffered *(ebp+0x10) %eax)
13645     (write-buffered *(ebp+0x10) "' must specify the type of array elements\n")
13646     (flush *(ebp+0x10))
13647     (stop *(ebp+0x14) 1)
13648     # never gets here
13649 
13650 $check-mu-index-stmt:error-index-on-stack:
13651     (write-buffered *(ebp+0x10) "fn ")
13652     8b/-> *(ebp+0xc) 0/r32/eax
13653     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13654     (write-buffered *(ebp+0x10) %eax)
13655     (write-buffered *(ebp+0x10) ": stmt index: second argument '")
13656     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13657     (write-buffered *(ebp+0x10) %eax)
13658     (write-buffered *(ebp+0x10) "' must be in a register\n")
13659     (flush *(ebp+0x10))
13660     (stop *(ebp+0x14) 1)
13661     # never gets here
13662 
13663 $check-mu-index-stmt:error-index-needs-offset:
13664     (write-buffered *(ebp+0x10) "fn ")
13665     8b/-> *(ebp+0xc) 0/r32/eax
13666     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13667     (write-buffered *(ebp+0x10) %eax)
13668     (write-buffered *(ebp+0x10) ": stmt index: cannot take an int for array '")
13669     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13670     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13671     (lookup *eax *(eax+4))  # Var-name Var-name => eax
13672     (write-buffered *(ebp+0x10) %eax)
13673     (write-buffered *(ebp+0x10) "'; create an offset instead. See mu_summary for details.\n")
13674     (flush *(ebp+0x10))
13675     (stop *(ebp+0x14) 1)
13676     # never gets here
13677 
13678 $check-mu-index-stmt:error-too-many-inouts:
13679     (write-buffered *(ebp+0x10) "fn ")
13680     8b/-> *(ebp+0xc) 0/r32/eax
13681     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13682     (write-buffered *(ebp+0x10) %eax)
13683     (write-buffered *(ebp+0x10) ": stmt index: too many inouts (2 required)\n")
13684     (flush *(ebp+0x10))
13685     (stop *(ebp+0x14) 1)
13686     # never gets here
13687 
13688 $check-mu-index-stmt:error-too-few-outputs:
13689     (write-buffered *(ebp+0x10) "fn ")
13690     8b/-> *(ebp+0xc) 0/r32/eax
13691     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13692     (write-buffered *(ebp+0x10) %eax)
13693     (write-buffered *(ebp+0x10) ": stmt index: must have an output\n")
13694     (flush *(ebp+0x10))
13695     (stop *(ebp+0x14) 1)
13696     # never gets here
13697 
13698 $check-mu-index-stmt:error-too-many-outputs:
13699     (write-buffered *(ebp+0x10) "fn ")
13700     8b/-> *(ebp+0xc) 0/r32/eax
13701     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13702     (write-buffered *(ebp+0x10) %eax)
13703     (write-buffered *(ebp+0x10) ": stmt index: too many outputs (1 required)\n")
13704     (flush *(ebp+0x10))
13705     (stop *(ebp+0x14) 1)
13706     # never gets here
13707 
13708 $check-mu-index-stmt:error-output-not-in-register:
13709     (write-buffered *(ebp+0x10) "fn ")
13710     8b/-> *(ebp+0xc) 0/r32/eax
13711     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13712     (write-buffered *(ebp+0x10) %eax)
13713     (write-buffered *(ebp+0x10) ": stmt index: output '")
13714     (lookup *edi *(edi+4))  # Var-name Var-name => eax
13715     (write-buffered *(ebp+0x10) %eax)
13716     (write-buffered *(ebp+0x10) "' is not in a register\n")
13717     (flush *(ebp+0x10))
13718     (stop *(ebp+0x14) 1)
13719     # never gets here
13720 
13721 $check-mu-index-stmt:error-output-type-not-address:
13722     (write-buffered *(ebp+0x10) "fn ")
13723     8b/-> *(ebp+0xc) 0/r32/eax
13724     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13725     (write-buffered *(ebp+0x10) %eax)
13726     (write-buffered *(ebp+0x10) ": stmt index: output '")
13727     (lookup *edi *(edi+4))  # Var-name Var-name => eax
13728     (write-buffered *(ebp+0x10) %eax)
13729     (write-buffered *(ebp+0x10) "' must be an address\n")
13730     (flush *(ebp+0x10))
13731     (stop *(ebp+0x14) 1)
13732     # never gets here
13733 
13734 $check-mu-index-stmt:error-bad-output-type:
13735     (write-buffered *(ebp+0x10) "fn ")
13736     8b/-> *(ebp+0xc) 0/r32/eax
13737     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13738     (write-buffered *(ebp+0x10) %eax)
13739     (write-buffered *(ebp+0x10) ": stmt index: output '")
13740     (lookup *edi *(edi+4))  # Var-name Var-name => eax
13741     (write-buffered *(ebp+0x10) %eax)
13742     (write-buffered *(ebp+0x10) "' does not have the right type\n")
13743     (flush *(ebp+0x10))
13744     (stop *(ebp+0x14) 1)
13745     # never gets here
13746 
13747 check-mu-length-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13748     # . prologue
13749     55/push-ebp
13750     89/<- %ebp 4/r32/esp
13751     # . save registers
13752 $check-mu-length-stmt:end:
13753     # . restore registers
13754     # . epilogue
13755     89/<- %esp 5/r32/ebp
13756     5d/pop-to-ebp
13757     c3/return
13758 
13759 check-mu-compute-offset-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13760     # . prologue
13761     55/push-ebp
13762     89/<- %ebp 4/r32/esp
13763     # . save registers
13764 $check-mu-compute-offset-stmt:end:
13765     # . restore registers
13766     # . epilogue
13767     89/<- %esp 5/r32/ebp
13768     5d/pop-to-ebp
13769     c3/return
13770 
13771 check-mu-allocate-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13772     # . prologue
13773     55/push-ebp
13774     89/<- %ebp 4/r32/esp
13775     # . save registers
13776 $check-mu-allocate-stmt:end:
13777     # . restore registers
13778     # . epilogue
13779     89/<- %esp 5/r32/ebp
13780     5d/pop-to-ebp
13781     c3/return
13782 
13783 check-mu-populate-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13784     # . prologue
13785     55/push-ebp
13786     89/<- %ebp 4/r32/esp
13787     # . save registers
13788 $check-mu-populate-stmt:end:
13789     # . restore registers
13790     # . epilogue
13791     89/<- %esp 5/r32/ebp
13792     5d/pop-to-ebp
13793     c3/return
13794 
13795 check-mu-populate-stream-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13796     # . prologue
13797     55/push-ebp
13798     89/<- %ebp 4/r32/esp
13799     # . save registers
13800 $check-mu-populate-stream-stmt:end:
13801     # . restore registers
13802     # . epilogue
13803     89/<- %esp 5/r32/ebp
13804     5d/pop-to-ebp
13805     c3/return
13806 
13807 check-mu-read-from-stream-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13808     # . prologue
13809     55/push-ebp
13810     89/<- %ebp 4/r32/esp
13811     # . save registers
13812 $check-mu-read-from-stream-stmt:end:
13813     # . restore registers
13814     # . epilogue
13815     89/<- %esp 5/r32/ebp
13816     5d/pop-to-ebp
13817     c3/return
13818 
13819 check-mu-write-to-stream-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13820     # . prologue
13821     55/push-ebp
13822     89/<- %ebp 4/r32/esp
13823     # . save registers
13824 $check-mu-write-to-stream-stmt:end:
13825     # . restore registers
13826     # . epilogue
13827     89/<- %esp 5/r32/ebp
13828     5d/pop-to-ebp
13829     c3/return
13830 
13831 check-mu-call:  # stmt: (addr stmt), callee: (addr function), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13832     # . prologue
13833     55/push-ebp
13834     89/<- %ebp 4/r32/esp
13835     # var type-parameters: (addr table (handle array byte) (addr type-tree) 8)
13836     68/push 0/imm32
13837     # var type-parameters-storage: (table (handle array byte) (addr type-tree) 8)
13838     81 5/subop/subtract %esp 0x60/imm32
13839     68/push 0x60/imm32/size
13840     68/push 0/imm32/read
13841     68/push 0/imm32/write
13842     # save a pointer to type-parameters-storage at type-parameters
13843     89/<- *(ebp-4) 4/r32/esp
13844     (clear-stream *(ebp-4))
13845     # . save registers
13846     50/push-eax
13847     51/push-ecx
13848     52/push-edx
13849     53/push-ebx
13850     56/push-esi
13851     57/push-edi
13852     # esi = stmt
13853     8b/-> *(ebp+8) 6/r32/esi
13854     # edi = callee
13855     8b/-> *(ebp+0xc) 7/r32/edi
13856     # var inouts/ecx: (addr stmt-var) = lookup(stmt->inouts)
13857     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13858     89/<- %ecx 0/r32/eax
13859     # var expected/edx: (addr list var) = lookup(f->inouts)
13860     (lookup *(edi+8) *(edi+0xc))  # Function-inouts Function-inouts => eax
13861     89/<- %edx 0/r32/eax
13862     {
13863 $check-mu-call:check-for-inouts:
13864       # if (inouts == 0) break
13865       81 7/subop/compare %ecx 0/imm32
13866       0f 84/jump-if-= break/disp32
13867       # if (expected == 0) error
13868       81 7/subop/compare %edx 0/imm32
13869       0f 84/jump-if-= break/disp32
13870 $check-mu-call:check-inout-type:
13871       # var v/eax: (addr v) = lookup(inouts->value)
13872       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
13873       # var t/ebx: (addr type-tree) = lookup(v->type)
13874       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
13875       89/<- %ebx 0/r32/eax
13876       # if (inouts->is-deref?) t = t->right  # TODO: check that t->left is an addr
13877       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
13878       {
13879         74/jump-if-= break/disp8
13880         (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
13881         89/<- %ebx 0/r32/eax
13882         # if t->right is null, t = t->left
13883         81 7/subop/compare *(ebx+0xc) 0/imm32  # Type-tree-right
13884         75/jump-if-!= break/disp8
13885         (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
13886         89/<- %ebx 0/r32/eax
13887       }
13888       # var v2/eax: (addr v) = lookup(expected->value)
13889       (lookup *edx *(edx+4))  # List-value List-value => eax
13890       # var t2/eax: (addr type-tree) = lookup(v2->type)
13891       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
13892       # if (t != t2) error
13893       (type-match? %eax %ebx *(ebp-4))  # => eax
13894       3d/compare-eax-and 0/imm32/false
13895       {
13896         0f 85/jump-if-!= break/disp32
13897         (write-buffered *(ebp+0x14) "fn ")
13898         8b/-> *(ebp+0x10) 0/r32/eax
13899         (lookup *eax *(eax+4))  # Function-name Function-name => eax
13900         (write-buffered *(ebp+0x14) %eax)
13901         (write-buffered *(ebp+0x14) ": call ")
13902         (lookup *edi *(edi+4))  # Function-name Function-name => eax
13903         (write-buffered *(ebp+0x14) %eax)
13904         (write-buffered *(ebp+0x14) ": type for inout '")
13905         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
13906         (lookup *eax *(eax+4))  # Var-name Var-name => eax
13907         (write-buffered *(ebp+0x14) %eax)
13908         (write-buffered *(ebp+0x14) "' is not right\n")
13909         (flush *(ebp+0x14))
13910         (stop *(ebp+0x18) 1)
13911       }
13912 $check-mu-call:continue-to-next-inout:
13913       # inouts = lookup(inouts->next)
13914       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
13915       89/<- %ecx 0/r32/eax
13916       # expected = lookup(expected->next)
13917       (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
13918       89/<- %edx 0/r32/eax
13919       #
13920       e9/jump loop/disp32
13921     }
13922 $check-mu-call:check-inout-count:
13923     # if (inouts == expected) proceed
13924     39/compare %ecx 2/r32/edx
13925     {
13926       0f 84/jump-if-= break/disp32
13927       # exactly one of the two is null
13928       # if (inouts == 0) error("too many inouts")
13929       {
13930         81 7/subop/compare %ecx 0/imm32
13931         0f 84/jump-if-= break/disp32
13932         (write-buffered *(ebp+0x14) "fn ")
13933         8b/-> *(ebp+0x10) 0/r32/eax
13934         (lookup *eax *(eax+4))  # Function-name Function-name => eax
13935         (write-buffered *(ebp+0x14) %eax)
13936         (write-buffered *(ebp+0x14) ": call ")
13937         (lookup *edi *(edi+4))  # Function-name Function-name => eax
13938         (write-buffered *(ebp+0x14) %eax)
13939         (write-buffered *(ebp+0x14) ": too many inouts\n")
13940         (flush *(ebp+0x14))
13941         (stop *(ebp+0x18) 1)
13942       }
13943       # if (expected == 0) error("too few inouts")
13944       {
13945         81 7/subop/compare %edx 0/imm32
13946         0f 84/jump-if-= break/disp32
13947         (write-buffered *(ebp+0x14) "fn ")
13948         8b/-> *(ebp+0x10) 0/r32/eax
13949         (lookup *eax *(eax+4))  # Function-name Function-name => eax
13950         (write-buffered *(ebp+0x14) %eax)
13951         (write-buffered *(ebp+0x14) ": call ")
13952         (lookup *edi *(edi+4))  # Function-name Function-name => eax
13953         (write-buffered *(ebp+0x14) %eax)
13954         (write-buffered *(ebp+0x14) ": too few inouts\n")
13955         (flush *(ebp+0x14))
13956         (stop *(ebp+0x18) 1)
13957       }
13958     }
13959 $check-mu-call:check-outputs:
13960     # var outputs/ecx: (addr stmt-var) = lookup(stmt->outputs)
13961     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13962     89/<- %ecx 0/r32/eax
13963     # var expected/edx: (addr list var) = lookup(f->outputs)
13964     (lookup *(edi+0x10) *(edi+0x14))  # Function-outputs Function-outputs => eax
13965     89/<- %edx 0/r32/eax
13966     {
13967 $check-mu-call:check-for-outputs:
13968       # if (outputs == 0) break
13969       81 7/subop/compare %ecx 0/imm32
13970       0f 84/jump-if-= break/disp32
13971       # if (expected == 0) error
13972       81 7/subop/compare %edx 0/imm32
13973       0f 84/jump-if-= break/disp32
13974 $check-mu-call:check-output-type:
13975       # var v/eax: (addr v) = lookup(outputs->value)
13976       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
13977       # var t/ebx: (addr type-tree) = lookup(v->type)
13978       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
13979       89/<- %ebx 0/r32/eax
13980       # if (outputs->is-deref?) t = t->right  # TODO: check that t->left is an addr
13981       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
13982       {
13983         74/jump-if-= break/disp8
13984         (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
13985         89/<- %ebx 0/r32/eax
13986       }
13987       # var v2/eax: (addr v) = lookup(expected->value)
13988       (lookup *edx *(edx+4))  # List-value List-value => eax
13989       # var t2/eax: (addr type-tree) = lookup(v2->type)
13990       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
13991       # if (t != t2) error
13992       (type-match? %eax %ebx *(ebp-4))  # => eax
13993       3d/compare-eax-and 0/imm32/false
13994       {
13995         0f 85/jump-if-!= break/disp32
13996         (write-buffered *(ebp+0x14) "fn ")
13997         8b/-> *(ebp+0x10) 0/r32/eax
13998         (lookup *eax *(eax+4))  # Function-name Function-name => eax
13999         (write-buffered *(ebp+0x14) %eax)
14000         (write-buffered *(ebp+0x14) ": call ")
14001         (lookup *edi *(edi+4))  # Function-name Function-name => eax
14002         (write-buffered *(ebp+0x14) %eax)
14003         (write-buffered *(ebp+0x14) ": type for output '")
14004         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
14005         (lookup *eax *(eax+4))  # Var-name Var-name => eax
14006         (write-buffered *(ebp+0x14) %eax)
14007         (write-buffered *(ebp+0x14) "' is not right\n")
14008         (flush *(ebp+0x14))
14009         (stop *(ebp+0x18) 1)
14010       }
14011 $check-mu-call:check-output-register:
14012       # var v/eax: (addr v) = lookup(outputs->value)
14013       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
14014       # var r/ebx: (addr array byte) = lookup(v->register)
14015       (lookup *(eax+18) *(eax+0x1c))  # Var-register Var-register => eax
14016       89/<- %ebx 0/r32/eax
14017       # var v2/eax: (addr v) = lookup(expected->value)
14018       (lookup *edx *(edx+4))  # Stmt-var-value Stmt-var-value => eax
14019       # var r2/eax: (addr array byte) = lookup(v2->register)
14020       (lookup *(eax+18) *(eax+0x1c))  # Var-register Var-register => eax
14021       # if (r != r2) error
14022       (string-equal? %eax %ebx)  # => eax
14023       3d/compare-eax-and 0/imm32/false
14024       {
14025         0f 85/jump-if-!= break/disp32
14026         (write-buffered *(ebp+0x14) "fn ")
14027         8b/-> *(ebp+0x10) 0/r32/eax
14028         (lookup *eax *(eax+4))  # Function-name Function-name => eax
14029         (write-buffered *(ebp+0x14) %eax)
14030         (write-buffered *(ebp+0x14) ": call ")
14031         (lookup *edi *(edi+4))  # Function-name Function-name => eax
14032         (write-buffered *(ebp+0x14) %eax)
14033         (write-buffered *(ebp+0x14) ": register for output '")
14034         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
14035         (lookup *eax *(eax+4))  # Var-name Var-name => eax
14036         (write-buffered *(ebp+0x14) %eax)
14037         (write-buffered *(ebp+0x14) "' is not right\n")
14038         (flush *(ebp+0x14))
14039         (stop *(ebp+0x18) 1)
14040       }
14041 $check-mu-call:continue-to-next-output:
14042       # outputs = lookup(outputs->next)
14043       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
14044       89/<- %ecx 0/r32/eax
14045       # expected = lookup(expected->next)
14046       (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
14047       89/<- %edx 0/r32/eax
14048       #
14049       e9/jump loop/disp32
14050     }
14051 $check-mu-call:check-output-count:
14052     # if (outputs == expected) proceed
14053     39/compare %ecx 2/r32/edx
14054     {
14055       0f 84/jump-if-= break/disp32
14056       # exactly one of the two is null
14057       # if (outputs == 0) error("too many outputs")
14058       {
14059         81 7/subop/compare %ecx 0/imm32
14060         0f 84/jump-if-= break/disp32
14061         (write-buffered *(ebp+0x14) "fn ")
14062         8b/-> *(ebp+0x10) 0/r32/eax
14063         (lookup *eax *(eax+4))  # Function-name Function-name => eax
14064         (write-buffered *(ebp+0x14) %eax)
14065         (write-buffered *(ebp+0x14) ": call ")
14066         (lookup *edi *(edi+4))  # Function-name Function-name => eax
14067         (write-buffered *(ebp+0x14) %eax)
14068         (write-buffered *(ebp+0x14) ": too many outputs\n")
14069         (flush *(ebp+0x14))
14070         (stop *(ebp+0x18) 1)
14071       }
14072       # if (expected == 0) error("too few outputs")
14073       {
14074         81 7/subop/compare %edx 0/imm32
14075         0f 84/jump-if-= break/disp32
14076         (write-buffered *(ebp+0x14) "fn ")
14077         8b/-> *(ebp+0x10) 0/r32/eax
14078         (lookup *eax *(eax+4))  # Function-name Function-name => eax
14079         (write-buffered *(ebp+0x14) %eax)
14080         (write-buffered *(ebp+0x14) ": call ")
14081         (lookup *edi *(edi+4))  # Function-name Function-name => eax
14082         (write-buffered *(ebp+0x14) %eax)
14083         (write-buffered *(ebp+0x14) ": too few outputs\n")
14084         (flush *(ebp+0x14))
14085         (stop *(ebp+0x18) 1)
14086       }
14087     }
14088 $check-mu-call:end:
14089     # . restore registers
14090     5f/pop-to-edi
14091     5e/pop-to-esi
14092     5b/pop-to-ebx
14093     5a/pop-to-edx
14094     59/pop-to-ecx
14095     58/pop-to-eax
14096     # . reclaim locals exclusively on the stack
14097     81 0/subop/add %esp 0x70/imm32
14098     # . epilogue
14099     89/<- %esp 5/r32/ebp
14100     5d/pop-to-ebp
14101     c3/return
14102 
14103 # like type-equal? but takes literals into account
14104 type-match?:  # def: (addr type-tree), call: (addr type-tree), type-parameters: (addr table (handle array byte) (addr type-tree)) -> result/eax: boolean
14105     # . prologue
14106     55/push-ebp
14107     89/<- %ebp 4/r32/esp
14108     # if (call == literal) return true  # TODO: more precise
14109     (is-simple-mu-type? *(ebp+0xc) 0)  # literal => eax
14110     3d/compare-eax-and 0/imm32/false
14111     b8/copy-to-eax 1/imm32/true
14112     75/jump-if-!= $type-match?:end/disp8
14113 $type-match?:baseline:
14114     # otherwise fall back
14115     (type-component-match? *(ebp+8) *(ebp+0xc) *(ebp+0x10))  # => eax
14116 $type-match?:end:
14117     # . epilogue
14118     89/<- %esp 5/r32/ebp
14119     5d/pop-to-ebp
14120     c3/return
14121 
14122 type-component-match?:  # def: (addr type-tree), call: (addr type-tree), type-parameters: (addr table (handle array byte) (addr type-tree)) -> result/eax: boolean
14123     # . prologue
14124     55/push-ebp
14125     89/<- %ebp 4/r32/esp
14126     # . save registers
14127     51/push-ecx
14128     52/push-edx
14129     53/push-ebx
14130     # ecx = def
14131     8b/-> *(ebp+8) 1/r32/ecx
14132     # edx = call
14133     8b/-> *(ebp+0xc) 2/r32/edx
14134 $type-component-match?:compare-addr:
14135     # if (def == call) return true
14136     8b/-> %ecx 0/r32/eax  # Var-type
14137     39/compare %edx 0/r32/eax  # Var-type
14138     b8/copy-to-eax 1/imm32/true
14139     0f 84/jump-if-= $type-component-match?:end/disp32
14140     # if (def == 0) return false
14141     b8/copy-to-eax 0/imm32/false
14142     81 7/subop/compare %ecx 0/imm32  # Type-tree-is-atom
14143     0f 84/jump-if-= $type-component-match?:end/disp32
14144     # if (call == 0) return false
14145     81 7/subop/compare %edx 0/imm32  # Type-tree-is-atom
14146     0f 84/jump-if-= $type-component-match?:end/disp32
14147     # if def is a type parameter, just check in type-parameters
14148     {
14149 $type-component-match?:check-type-parameter:
14150       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
14151       74/jump-if-= break/disp8
14152       81 7/subop/compare *(ecx+4) 0xa/imm32/type-parameter  # Type-tree-value
14153       75/jump-if-!= break/disp8
14154 $type-component-match?:type-parameter:
14155       (type-parameter-match? *(ecx+8) *(ecx+0xc)  %edx  *(ebp+0x10))  # => eax
14156       e9/jump $type-component-match?:end/disp32
14157     }
14158     # if def is a list containing just a type parameter, just check in type-parameters
14159     {
14160 $type-component-match?:check-list-type-parameter:
14161       # if def is a list..
14162       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
14163       75/jump-if-!= break/disp8
14164       #   ..that's a singleton
14165       81 7/subop/compare *(ecx+0xc) 0/imm32  # Type-tree-left
14166       75/jump-if-!= break/disp8
14167       #   ..and whose head is a type parameter
14168       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14169       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14170       74/jump-if-= break/disp8
14171       81 7/subop/compare *(eax+4) 0xa/imm32/type-parameter  # Type-tree-value
14172       75/jump-if-!= break/disp8
14173 $type-component-match?:list-type-parameter:
14174       (type-parameter-match? *(eax+8) *(eax+0xc)  %edx  *(ebp+0x10))  # => eax
14175       e9/jump $type-component-match?:end/disp32
14176     }
14177 $type-component-match?:compare-atom-state:
14178     # if (def->is-atom? != call->is-atom?) return false
14179     8b/-> *ecx 3/r32/ebx  # Type-tree-is-atom
14180     39/compare *edx 3/r32/ebx  # Type-tree-is-atom
14181     b8/copy-to-eax 0/imm32/false
14182     0f 85/jump-if-!= $type-component-match?:end/disp32
14183     # if def->is-atom? return (def->value == call->value)
14184     {
14185 $type-component-match?:check-atom:
14186       81 7/subop/compare %ebx 0/imm32/false
14187       74/jump-if-= break/disp8
14188 $type-component-match?:is-atom:
14189       8b/-> *(ecx+4) 0/r32/eax  # Type-tree-value
14190       39/compare *(edx+4) 0/r32/eax  # Type-tree-value
14191       0f 94/set-if-= %al
14192       81 4/subop/and %eax 0xff/imm32
14193       e9/jump $type-component-match?:end/disp32
14194     }
14195 $type-component-match?:check-left:
14196     # if (!type-component-match?(def->left, call->left)) return false
14197     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14198     89/<- %ebx 0/r32/eax
14199     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
14200     (type-component-match? %ebx %eax *(ebp+0x10))  # => eax
14201     3d/compare-eax-and 0/imm32/false
14202     74/jump-if-= $type-component-match?:end/disp8
14203 $type-component-match?:check-right:
14204     # return type-component-match?(def->right, call->right)
14205     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
14206     89/<- %ebx 0/r32/eax
14207     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
14208     (type-component-match? %ebx %eax *(ebp+0x10))  # => eax
14209 $type-component-match?:end:
14210     # . restore registers
14211     5b/pop-to-ebx
14212     5a/pop-to-edx
14213     59/pop-to-ecx
14214     # . epilogue
14215     89/<- %esp 5/r32/ebp
14216     5d/pop-to-ebp
14217     c3/return
14218 
14219 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
14220     # . prologue
14221     55/push-ebp
14222     89/<- %ebp 4/r32/esp
14223     # . save registers
14224     51/push-ecx
14225     #
14226     (get-or-insert-handle *(ebp+0x14)  *(ebp+8) *(ebp+0xc)  0xc)  # => eax
14227     # if parameter wasn't saved, save it
14228     {
14229       81 7/subop/compare *eax 0/imm32
14230       75/jump-if-!= break/disp8
14231       8b/-> *(ebp+0x10) 1/r32/ecx
14232       89/<- *eax 1/r32/ecx
14233     }
14234     #
14235     (type-equal? *(ebp+0x10) *eax)  # => eax
14236 $type-parameter-match?:end:
14237     # . restore registers
14238     59/pop-to-ecx
14239     # . epilogue
14240     89/<- %esp 5/r32/ebp
14241     5d/pop-to-ebp
14242     c3/return
14243 
14244 size-of:  # v: (addr var) -> result/eax: int
14245     # . prologue
14246     55/push-ebp
14247     89/<- %ebp 4/r32/esp
14248     # . save registers
14249     51/push-ecx
14250     # var t/ecx: (addr type-tree) = lookup(v->type)
14251     8b/-> *(ebp+8) 1/r32/ecx
14252 #?     (write-buffered Stderr "size-of ")
14253 #?     (write-int32-hex-buffered Stderr %ecx)
14254 #?     (write-buffered Stderr Newline)
14255 #?     (write-buffered Stderr "type allocid: ")
14256 #?     (write-int32-hex-buffered Stderr *(ecx+8))
14257 #?     (write-buffered Stderr Newline)
14258 #?     (flush Stderr)
14259     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
14260     89/<- %ecx 0/r32/eax
14261     # if is-mu-array?(t) return size-of-array(t)
14262     {
14263       (is-mu-array? %ecx)  # => eax
14264       3d/compare-eax-and 0/imm32/false
14265       74/jump-if-= break/disp8
14266       (size-of-array %ecx)  # => eax
14267       eb/jump $size-of:end/disp8
14268     }
14269     # if is-mu-stream?(t) return size-of-stream(t)
14270     {
14271       (is-mu-stream? %ecx)  # => eax
14272       3d/compare-eax-and 0/imm32/false
14273       74/jump-if-= break/disp8
14274       (size-of-stream %ecx)  # => eax
14275       eb/jump $size-of:end/disp8
14276     }
14277     # if (!t->is-atom?) t = lookup(t->left)
14278     {
14279       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
14280       75/jump-if-!= break/disp8
14281       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14282       89/<- %ecx 0/r32/eax
14283     }
14284     # TODO: assert t->is-atom?
14285     (size-of-type-id *(ecx+4))  # Type-tree-value => eax
14286 $size-of:end:
14287     # . restore registers
14288     59/pop-to-ecx
14289     # . epilogue
14290     89/<- %esp 5/r32/ebp
14291     5d/pop-to-ebp
14292     c3/return
14293 
14294 size-of-deref:  # v: (addr var) -> result/eax: int
14295     # . prologue
14296     55/push-ebp
14297     89/<- %ebp 4/r32/esp
14298     # . save registers
14299     51/push-ecx
14300     # var t/ecx: (addr type-tree) = lookup(v->type)
14301     8b/-> *(ebp+8) 1/r32/ecx
14302     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
14303     89/<- %ecx 0/r32/eax
14304     # TODO: assert(t is an addr)
14305     # t = lookup(t->right)
14306     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
14307     89/<- %ecx 0/r32/eax
14308     # if is-mu-array?(t) return size-of-array(t)
14309     {
14310       (is-mu-array? %ecx)  # => eax
14311       3d/compare-eax-and 0/imm32/false
14312       74/jump-if-= break/disp8
14313       (size-of-array %ecx)  # => eax
14314       eb/jump $size-of-deref:end/disp8
14315     }
14316     # if is-mu-stream?(t) return size-of-stream(t)
14317     {
14318       (is-mu-stream? %ecx)  # => eax
14319       3d/compare-eax-and 0/imm32/false
14320       74/jump-if-= break/disp8
14321       (size-of-stream %ecx)  # => eax
14322       eb/jump $size-of-deref:end/disp8
14323     }
14324     # if (!t->is-atom?) t = lookup(t->left)
14325     {
14326       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
14327       75/jump-if-!= break/disp8
14328       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14329       89/<- %ecx 0/r32/eax
14330     }
14331     # TODO: assert t->is-atom?
14332     (size-of-type-id *(ecx+4))  # Type-tree-value => eax
14333 $size-of-deref:end:
14334     # . restore registers
14335     59/pop-to-ecx
14336     # . epilogue
14337     89/<- %esp 5/r32/ebp
14338     5d/pop-to-ebp
14339     c3/return
14340 
14341 is-mu-array?:  # t: (addr type-tree) -> result/eax: boolean
14342     # . prologue
14343     55/push-ebp
14344     89/<- %ebp 4/r32/esp
14345     # . save registers
14346     51/push-ecx
14347     # ecx = t
14348     8b/-> *(ebp+8) 1/r32/ecx
14349     # if t->is-atom?, return false
14350     81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
14351     75/jump-if-!= $is-mu-array?:return-false/disp8
14352     # if !t->left->is-atom?, return false
14353     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14354     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14355     74/jump-if-= $is-mu-array?:return-false/disp8
14356     # return t->left->value == array
14357     81 7/subop/compare *(eax+4) 3/imm32/array-type-id  # Type-tree-value
14358     0f 94/set-if-= %al
14359     81 4/subop/and %eax 0xff/imm32
14360     eb/jump $is-mu-array?:end/disp8
14361 $is-mu-array?:return-false:
14362     b8/copy-to-eax 0/imm32/false
14363 $is-mu-array?:end:
14364     # . restore registers
14365     59/pop-to-ecx
14366     # . epilogue
14367     89/<- %esp 5/r32/ebp
14368     5d/pop-to-ebp
14369     c3/return
14370 
14371 # size of a statically allocated array where the size is part of the type expression
14372 size-of-array:  # a: (addr type-tree) -> result/eax: int
14373     # . prologue
14374     55/push-ebp
14375     89/<- %ebp 4/r32/esp
14376     # . save registers
14377     51/push-ecx
14378     52/push-edx
14379     #
14380     8b/-> *(ebp+8) 1/r32/ecx
14381     # TODO: assert that a->left is 'array'
14382     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
14383     89/<- %ecx 0/r32/eax
14384     # var elem-type/edx: type-id = a->right->left->value
14385     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14386     8b/-> *(eax+4) 2/r32/edx  # Type-tree-value
14387     # TODO: assert that a->right->right->left->value == size
14388     # var array-size/ecx: int = a->right->right->left->value-size
14389     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
14390     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
14391     8b/-> *(eax+8) 1/r32/ecx  # Type-tree-value-size
14392     # return 4 + array-size * size-of(elem-type)
14393     (size-of-type-id-as-array-element %edx)  # => eax
14394     f7 4/subop/multiply-into-eax %ecx
14395     05/add-to-eax 4/imm32  # for array size
14396 $size-of-array:end:
14397     # . restore registers
14398     5a/pop-to-edx
14399     59/pop-to-ecx
14400     # . epilogue
14401     89/<- %esp 5/r32/ebp
14402     5d/pop-to-ebp
14403     c3/return
14404 
14405 is-mu-stream?:  # t: (addr type-tree) -> result/eax: boolean
14406     # . prologue
14407     55/push-ebp
14408     89/<- %ebp 4/r32/esp
14409     # . save registers
14410     51/push-ecx
14411     # ecx = t
14412     8b/-> *(ebp+8) 1/r32/ecx
14413     # if t->is-atom?, return false
14414     81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
14415     75/jump-if-!= $is-mu-stream?:return-false/disp8
14416     # if !t->left->is-atom?, return false
14417     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14418     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14419     74/jump-if-= $is-mu-stream?:return-false/disp8
14420     # return t->left->value == stream
14421     81 7/subop/compare *(eax+4) 0xb/imm32/stream-type-id  # Type-tree-value
14422     0f 94/set-if-= %al
14423     81 4/subop/and %eax 0xff/imm32
14424     eb/jump $is-mu-stream?:end/disp8
14425 $is-mu-stream?:return-false:
14426     b8/copy-to-eax 0/imm32/false
14427 $is-mu-stream?:end:
14428     # . restore registers
14429     59/pop-to-ecx
14430     # . epilogue
14431     89/<- %esp 5/r32/ebp
14432     5d/pop-to-ebp
14433     c3/return
14434 
14435 # size of a statically allocated stream where the size is part of the type expression
14436 size-of-stream:  # a: (addr type-tree) -> result/eax: int
14437     # . prologue
14438     55/push-ebp
14439     89/<- %ebp 4/r32/esp
14440     #
14441     (size-of-array *(ebp+8))  # assumes we ignore the actual type name 'array' in the type
14442     05/add-to-eax 8/imm32  # for read/write pointers
14443 $size-of-stream:end:
14444     # . epilogue
14445     89/<- %esp 5/r32/ebp
14446     5d/pop-to-ebp
14447     c3/return
14448 
14449 size-of-type-id:  # t: type-id -> result/eax: int
14450     # . prologue
14451     55/push-ebp
14452     89/<- %ebp 4/r32/esp
14453     # . save registers
14454     51/push-ecx
14455     # var out/ecx: (handle typeinfo)
14456     68/push 0/imm32
14457     68/push 0/imm32
14458     89/<- %ecx 4/r32/esp
14459     # eax = t
14460     8b/-> *(ebp+8) 0/r32/eax
14461     # if t is a literal, return 0
14462     3d/compare-eax-and 0/imm32
14463     0f 84/jump-if-= $size-of-type-id:end/disp32  # eax changes type from type-id to int
14464     # if t is a byte, return 4 (because we don't really support non-multiples of 4)
14465     3d/compare-eax-and 8/imm32/byte
14466     {
14467       75/jump-if-!= break/disp8
14468       b8/copy-to-eax 4/imm32
14469       eb/jump $size-of-type-id:end/disp8
14470     }
14471     # if t is a handle, return 8
14472     3d/compare-eax-and 4/imm32/handle
14473     {
14474       75/jump-if-!= break/disp8
14475       b8/copy-to-eax 8/imm32
14476       eb/jump $size-of-type-id:end/disp8  # eax changes type from type-id to int
14477     }
14478     # if t is a user-defined type, return its size
14479     # TODO: support non-atom type
14480     (find-typeinfo %eax %ecx)
14481     {
14482       81 7/subop/compare *ecx 0/imm32
14483       74/jump-if-= break/disp8
14484 $size-of-type-id:user-defined:
14485       (lookup *ecx *(ecx+4))  # => eax
14486       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
14487       eb/jump $size-of-type-id:end/disp8
14488     }
14489     # otherwise return the word size
14490     b8/copy-to-eax 4/imm32
14491 $size-of-type-id:end:
14492     # . reclaim locals
14493     81 0/subop/add %esp 8/imm32
14494     # . restore registers
14495     59/pop-to-ecx
14496     # . epilogue
14497     89/<- %esp 5/r32/ebp
14498     5d/pop-to-ebp
14499     c3/return
14500 
14501 # Minor violation of our type system since it returns an addr. But we could
14502 # replace it with a handle some time.
14503 # Returns null if t is an atom.
14504 type-tail:  # t: (addr type-tree) -> out/eax: (addr type-tree)
14505     # . prologue
14506     55/push-ebp
14507     89/<- %ebp 4/r32/esp
14508     # . save registers
14509     51/push-ecx
14510     # eax = 0
14511     b8/copy-to-eax 0/imm32
14512     # ecx = t
14513     8b/-> *(ebp+8) 1/r32/ecx
14514 $type-tail:check-atom:
14515     # if t->is-atom? return 0
14516     81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
14517     0f 85/jump-if-!= $type-tail:end/disp32
14518     # var tail = t->right
14519     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
14520     89/<- %ecx 0/r32/eax
14521 $type-tail:check-singleton:
14522     # if (tail->right == 0) return tail->left
14523     {
14524       81 7/subop/compare *(ecx+0xc) 0/imm32  # Type-tree-right
14525       75/jump-if-!= break/disp8
14526       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14527       e9/jump $type-tail:end/disp32
14528     }
14529     # if tail->right->left is an array-capacity, return tail->left
14530     {
14531 $type-tail:check-array-capacity:
14532       (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
14533       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14534       75/jump-if-!= break/disp8
14535 $type-tail:check-array-capacity-1:
14536       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
14537       3d/compare-eax-and 0/imm32
14538       74/jump-if-= break/disp8
14539 $type-tail:check-array-capacity-2:
14540       (is-simple-mu-type? %eax 9)  # array-capacity => eax
14541       3d/compare-eax-and 0/imm32/false
14542       74/jump-if-= break/disp8
14543 $type-tail:array-capacity:
14544       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14545       eb/jump $type-tail:end/disp8
14546     }
14547 $type-tail:check-compound-left:
14548     # if !tail->left->is-atom? return tail->left
14549     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14550     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14551     74/jump-if-= $type-tail:end/disp8
14552 $type-tail:return-tail:
14553     # return tail
14554     89/<- %eax 1/r32/ecx
14555 $type-tail:end:
14556     # . restore registers
14557     59/pop-to-ecx
14558     # . epilogue
14559     89/<- %esp 5/r32/ebp
14560     5d/pop-to-ebp
14561     c3/return
14562 
14563 type-equal?:  # a: (addr type-tree), b: (addr type-tree) -> result/eax: boolean
14564     # . prologue
14565     55/push-ebp
14566     89/<- %ebp 4/r32/esp
14567     # . save registers
14568     51/push-ecx
14569     52/push-edx
14570     53/push-ebx
14571     # ecx = a
14572     8b/-> *(ebp+8) 1/r32/ecx
14573     # edx = b
14574     8b/-> *(ebp+0xc) 2/r32/edx
14575 $type-equal?:compare-addr:
14576     # if (a == b) return true
14577     8b/-> %ecx 0/r32/eax  # Var-type
14578     39/compare %edx 0/r32/eax  # Var-type
14579     b8/copy-to-eax 1/imm32/true
14580     0f 84/jump-if-= $type-equal?:end/disp32
14581 $type-equal?:compare-null-a:
14582     # if (a == 0) return false
14583     b8/copy-to-eax 0/imm32/false
14584     81 7/subop/compare %ecx 0/imm32
14585     0f 84/jump-if-= $type-equal?:end/disp32
14586 $type-equal?:compare-null-b:
14587     # if (b == 0) return false
14588     81 7/subop/compare %edx 0/imm32
14589     0f 84/jump-if-= $type-equal?:end/disp32
14590 $type-equal?:compare-atom-state:
14591     # if (a->is-atom? != b->is-atom?) return false
14592     8b/-> *ecx 3/r32/ebx  # Type-tree-is-atom
14593     39/compare *edx 3/r32/ebx  # Type-tree-is-atom
14594     b8/copy-to-eax 0/imm32/false
14595     0f 85/jump-if-!= $type-equal?:end/disp32
14596     # if a->is-atom? return (a->value == b->value)
14597     {
14598 $type-equal?:check-atom:
14599       81 7/subop/compare %ebx 0/imm32/false
14600       74/jump-if-= break/disp8
14601 $type-equal?:is-atom:
14602       8b/-> *(ecx+4) 0/r32/eax  # Type-tree-value
14603       39/compare *(edx+4) 0/r32/eax  # Type-tree-value
14604       0f 94/set-if-= %al
14605       81 4/subop/and %eax 0xff/imm32
14606       e9/jump $type-equal?:end/disp32
14607     }
14608 $type-equal?:check-left:
14609     # if (!type-equal?(a->left, b->left)) return false
14610     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14611     89/<- %ebx 0/r32/eax
14612     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
14613     (type-equal? %eax %ebx)  # => eax
14614     3d/compare-eax-and 0/imm32/false
14615     74/jump-if-= $type-equal?:end/disp8
14616 $type-equal?:check-right:
14617     # return type-equal?(a->right, b->right)
14618     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
14619     89/<- %ebx 0/r32/eax
14620     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
14621     (type-equal? %eax %ebx)  # => eax
14622 $type-equal?:end:
14623     # . restore registers
14624     5b/pop-to-ebx
14625     5a/pop-to-edx
14626     59/pop-to-ecx
14627     # . epilogue
14628     89/<- %esp 5/r32/ebp
14629     5d/pop-to-ebp
14630     c3/return
14631 
14632 #######################################################
14633 # Code-generation
14634 #######################################################
14635 
14636 == data
14637 
14638 # Global state added to each var record when performing code-generation.
14639 Curr-local-stack-offset:  # (addr int)
14640     0/imm32
14641 
14642 == code
14643 
14644 emit-subx:  # out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
14645     # . prologue
14646     55/push-ebp
14647     89/<- %ebp 4/r32/esp
14648     # . save registers
14649     50/push-eax
14650     # var curr/eax: (addr function) = *Program->functions
14651     (lookup *_Program-functions *_Program-functions->payload)  # => eax
14652     {
14653       # if (curr == null) break
14654       3d/compare-eax-and 0/imm32
14655       0f 84/jump-if-= break/disp32
14656       (emit-subx-function *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))
14657       # curr = lookup(curr->next)
14658       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
14659       e9/jump loop/disp32
14660     }
14661 $emit-subx:end:
14662     # . restore registers
14663     58/pop-to-eax
14664     # . epilogue
14665     89/<- %esp 5/r32/ebp
14666     5d/pop-to-ebp
14667     c3/return
14668 
14669 emit-subx-function:  # out: (addr buffered-file), f: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
14670     # . prologue
14671     55/push-ebp
14672     89/<- %ebp 4/r32/esp
14673     # some preprocessing
14674     (populate-mu-type-offsets-in-inouts *(ebp+0xc))
14675     # . save registers
14676     50/push-eax
14677     51/push-ecx
14678     52/push-edx
14679     # initialize some global state
14680     c7 0/subop/copy *Curr-block-depth 1/imm32  # Important: keep this in sync with the parse phase
14681     c7 0/subop/copy *Curr-local-stack-offset 0/imm32
14682     # ecx = f
14683     8b/-> *(ebp+0xc) 1/r32/ecx
14684     # var vars/edx: (stack (addr var) 256)
14685     81 5/subop/subtract %esp 0xc00/imm32
14686     68/push 0xc00/imm32/size
14687     68/push 0/imm32/top
14688     89/<- %edx 4/r32/esp
14689     # var name/eax: (addr array byte) = lookup(f->name)
14690     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
14691     #
14692     (write-buffered *(ebp+8) %eax)
14693     (write-buffered *(ebp+8) ":\n")
14694     (emit-subx-prologue *(ebp+8))
14695     # var body/eax: (addr block) = lookup(f->body)
14696     (lookup *(ecx+0x18) *(ecx+0x1c))  # Function-body Function-body => eax
14697     #
14698     (emit-subx-block *(ebp+8) %eax %edx *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
14699     (emit-subx-epilogue *(ebp+8))
14700     # TODO: validate that *Curr-block-depth and *Curr-local-stack-offset have
14701     # been cleaned up
14702 $emit-subx-function:end:
14703     # . reclaim locals
14704     81 0/subop/add %esp 0xc08/imm32
14705     # . restore registers
14706     5a/pop-to-edx
14707     59/pop-to-ecx
14708     58/pop-to-eax
14709     # . epilogue
14710     89/<- %esp 5/r32/ebp
14711     5d/pop-to-ebp
14712     c3/return
14713 
14714 populate-mu-type-offsets-in-inouts:  # f: (addr function)
14715     # . prologue
14716     55/push-ebp
14717     89/<- %ebp 4/r32/esp
14718     # . save registers
14719     50/push-eax
14720     51/push-ecx
14721     52/push-edx
14722     53/push-ebx
14723     57/push-edi
14724     # var next-offset/edx: int = 8
14725     ba/copy-to-edx 8/imm32
14726     # var curr/ecx: (addr list var) = lookup(f->inouts)
14727     8b/-> *(ebp+8) 1/r32/ecx
14728     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
14729     89/<- %ecx 0/r32/eax
14730     {
14731 $populate-mu-type-offsets-in-inouts:loop:
14732       81 7/subop/compare %ecx 0/imm32
14733       74/jump-if-= break/disp8
14734       # var v/ebx: (addr var) = lookup(curr->value)
14735       (lookup *ecx *(ecx+4))  # List-value List-value => eax
14736       89/<- %ebx 0/r32/eax
14737 #?       (lookup *ebx *(ebx+4))
14738 #?       (write-buffered Stderr "setting offset of fn inout ")
14739 #?       (write-buffered Stderr %eax)
14740 #?       (write-buffered Stderr "@")
14741 #?       (write-int32-hex-buffered Stderr %ebx)
14742 #?       (write-buffered Stderr " to ")
14743 #?       (write-int32-hex-buffered Stderr %edx)
14744 #?       (write-buffered Stderr Newline)
14745 #?       (flush Stderr)
14746       # v->offset = next-offset
14747       89/<- *(ebx+0x14) 2/r32/edx  # Var-offset
14748       # next-offset += size-of(v)
14749       (size-of %ebx)  # => eax
14750       01/add-to %edx 0/r32/eax
14751       # curr = lookup(curr->next)
14752       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
14753       89/<- %ecx 0/r32/eax
14754       #
14755       eb/jump loop/disp8
14756     }
14757 $populate-mu-type-offsets-in-inouts:end:
14758     # . restore registers
14759     5f/pop-to-edi
14760     5b/pop-to-ebx
14761     5a/pop-to-edx
14762     59/pop-to-ecx
14763     58/pop-to-eax
14764     # . epilogue
14765     89/<- %esp 5/r32/ebp
14766     5d/pop-to-ebp
14767     c3/return
14768 
14769 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)
14770     # . prologue
14771     55/push-ebp
14772     89/<- %ebp 4/r32/esp
14773     # . save registers
14774     50/push-eax
14775     51/push-ecx
14776     53/push-ebx
14777     56/push-esi
14778     # esi = stmts
14779     8b/-> *(ebp+0xc) 6/r32/esi
14780     #
14781     {
14782 $emit-subx-stmt-list:loop:
14783       81 7/subop/compare %esi 0/imm32
14784       0f 84/jump-if-= break/disp32
14785       # var curr-stmt/ecx: (addr stmt) = lookup(stmts->value)
14786       (lookup *esi *(esi+4))  # List-value List-value => eax
14787       89/<- %ecx 0/r32/eax
14788       {
14789 $emit-subx-stmt-list:check-for-block:
14790         81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
14791         75/jump-if-!= break/disp8
14792 $emit-subx-stmt-list:block:
14793         (emit-subx-block *(ebp+8) %ecx *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
14794       }
14795       {
14796 $emit-subx-stmt-list:check-for-stmt:
14797         81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
14798         0f 85/jump-if-!= break/disp32
14799 $emit-subx-stmt-list:stmt1:
14800         {
14801           (is-mu-branch? %ecx)  # => eax
14802           3d/compare-eax-and 0/imm32/false
14803           0f 84/jump-if-= break/disp32
14804 $emit-subx-stmt-list:branch-stmt:
14805 +-- 27 lines: # unconditional loops -----------------------------------------------------------------------------------------------------------------------------------------------------
14832 +-- 16 lines: # unconditional breaks ----------------------------------------------------------------------------------------------------------------------------------------------------
14848 +-- 38 lines: # simple conditional branches without a target ----------------------------------------------------------------------------------------------------------------------------
14886 +-- 19 lines: # conditional branches with an explicit target ----------------------------------------------------------------------------------------------------------------------------
14905         }
14906 $emit-subx-stmt-list:1-to-1:
14907         (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x18) *(ebp+0x1c))
14908         e9/jump $emit-subx-stmt-list:continue/disp32
14909       }
14910       {
14911 $emit-subx-stmt-list:check-for-var-def:
14912         81 7/subop/compare *ecx 2/imm32/var-def  # Stmt-tag
14913         75/jump-if-!= break/disp8
14914 $emit-subx-stmt-list:var-def:
14915         (emit-subx-var-def *(ebp+8) %ecx)
14916         (push *(ebp+0x10) *(ecx+4))  # Vardef-var
14917         (push *(ebp+0x10) *(ecx+8))  # Vardef-var
14918         (push *(ebp+0x10) 0)  # Live-var-register-spilled = 0 for vars on the stack
14919         #
14920         eb/jump $emit-subx-stmt-list:continue/disp8
14921       }
14922       {
14923 $emit-subx-stmt-list:check-for-reg-var-def:
14924         81 7/subop/compare *ecx 3/imm32/reg-var-def  # Stmt-tag
14925         0f 85/jump-if-!= break/disp32
14926 $emit-subx-stmt-list:reg-var-def:
14927         # TODO: ensure that there's exactly one output
14928         (push-output-and-maybe-emit-spill *(ebp+8) %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
14929         # emit the instruction as usual
14930         (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x18) *(ebp+0x1c))
14931         #
14932         eb/jump $emit-subx-stmt-list:continue/disp8
14933       }
14934 $emit-subx-stmt-list:continue:
14935       # TODO: raise an error on unrecognized Stmt-tag
14936       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
14937       89/<- %esi 0/r32/eax
14938       e9/jump loop/disp32
14939     }
14940 $emit-subx-stmt-list:emit-cleanup:
14941     (emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth)
14942 $emit-subx-stmt-list:clean-up:
14943     (clean-up-blocks *(ebp+0x10) *Curr-block-depth *(ebp+0x14))
14944 $emit-subx-stmt-list:end:
14945     # . restore registers
14946     5e/pop-to-esi
14947     5b/pop-to-ebx
14948     59/pop-to-ecx
14949     58/pop-to-eax
14950     # . epilogue
14951     89/<- %esp 5/r32/ebp
14952     5d/pop-to-ebp
14953     c3/return
14954 
14955 # 'later-stmts' includes 'stmt', but will behave the same even without it; reg-var-def stmts are guaranteed not to write to function outputs.
14956 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)
14957     # . prologue
14958     55/push-ebp
14959     89/<- %ebp 4/r32/esp
14960     # . save registers
14961     50/push-eax
14962     51/push-ecx
14963     52/push-edx
14964     # ecx = stmt
14965     8b/-> *(ebp+0xc) 1/r32/ecx
14966     # var sv/eax: (addr stmt-var) = lookup(curr-stmt->outputs)
14967     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
14968     # TODO: assert !sv->is-deref?
14969     # var v/ecx: (addr var) = lookup(sv->value)
14970     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
14971     89/<- %ecx 0/r32/eax
14972     # v->block-depth = *Curr-block-depth
14973     8b/-> *Curr-block-depth 0/r32/eax
14974     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
14975 #?     (write-buffered Stderr "var ")
14976 #?     (lookup *ecx *(ecx+4))
14977 #?     (write-buffered Stderr %eax)
14978 #?     (write-buffered Stderr " at depth ")
14979 #?     (write-int32-hex-buffered Stderr *(ecx+0x10))
14980 #?     (write-buffered Stderr Newline)
14981 #?     (flush Stderr)
14982     # ensure that v is in a register
14983     81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
14984     0f 84/jump-if-= $push-output-and-maybe-emit-spill:abort/disp32
14985     # var emit-spill?/edx: boolean = not-yet-spilled-this-block? && will-not-write-some-register?(fn)
14986     (not-yet-spilled-this-block? %ecx *(ebp+0x10))  # => eax
14987     89/<- %edx 0/r32/eax
14988     3d/compare-eax-and 0/imm32/false
14989     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
14990     (will-not-write-some-register? %ecx *(ebp+0x14) *(ebp+0x18))  # => eax
14991     89/<- %edx 0/r32/eax
14992     # check emit-spill?
14993     3d/compare-eax-and 0/imm32/false
14994     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
14995     # TODO: assert(size-of(output) == 4)
14996     # *Curr-local-stack-offset -= 4
14997     81 5/subop/subtract *Curr-local-stack-offset 4/imm32
14998     # emit spill
14999     (emit-indent *(ebp+8) *Curr-block-depth)
15000     (write-buffered *(ebp+8) "ff 6/subop/push %")
15001     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
15002     (write-buffered *(ebp+8) %eax)
15003     (write-buffered *(ebp+8) Newline)
15004 $push-output-and-maybe-emit-spill:push:
15005     8b/-> *(ebp+0xc) 1/r32/ecx
15006     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
15007     # push(vars, {sv->value, emit-spill?})
15008     (push *(ebp+0x10) *eax)  # Stmt-var-value
15009     (push *(ebp+0x10) *(eax+4))  # Stmt-var-value
15010     (push *(ebp+0x10) %edx)
15011 $push-output-and-maybe-emit-spill:end:
15012     # . restore registers
15013     5a/pop-to-edx
15014     59/pop-to-ecx
15015     58/pop-to-eax
15016     # . epilogue
15017     89/<- %esp 5/r32/ebp
15018     5d/pop-to-ebp
15019     c3/return
15020 
15021 $push-output-and-maybe-emit-spill:abort:
15022     # error("var '" var->name "' initialized from an instruction must live in a register\n")
15023     (write-buffered *(ebp+0x1c) "var '")
15024     (write-buffered *(ebp+0x1c) *eax)  # Var-name
15025     (write-buffered *(ebp+0x1c) "' initialized from an instruction must live in a register\n")
15026     (flush *(ebp+0x1c))
15027     (stop *(ebp+0x20) 1)
15028     # never gets here
15029 
15030 emit-subx-cleanup-and-unconditional-nonlocal-branch:  # out: (addr buffered-file), stmt: (addr stmt1), vars: (addr stack live-var)
15031     # . prologue
15032     55/push-ebp
15033     89/<- %ebp 4/r32/esp
15034     # . save registers
15035     50/push-eax
15036     51/push-ecx
15037     # ecx = stmt
15038     8b/-> *(ebp+0xc) 1/r32/ecx
15039     # var target/eax: (addr array byte) = curr-stmt->inouts->value->name
15040     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15041     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15042     (lookup *eax *(eax+4))  # Var-name Var-name => eax
15043     # clean up until target block
15044     (emit-cleanup-code-until-target *(ebp+8) *(ebp+0x10) %eax)
15045     # emit jump to target block
15046     (emit-indent *(ebp+8) *Curr-block-depth)
15047     (write-buffered *(ebp+8) "e9/jump ")
15048     (write-buffered *(ebp+8) %eax)
15049     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
15050     (string-starts-with? %eax "break")
15051     3d/compare-eax-and 0/imm32/false
15052     {
15053       74/jump-if-= break/disp8
15054       (write-buffered *(ebp+8) ":break/disp32\n")
15055     }
15056     3d/compare-eax-and 0/imm32/false  # just in case the function call modified flags
15057     {
15058       75/jump-if-!= break/disp8
15059       (write-buffered *(ebp+8) ":loop/disp32\n")
15060     }
15061 $emit-subx-cleanup-and-unconditional-nonlocal-branch:end:
15062     # . restore registers
15063     59/pop-to-ecx
15064     58/pop-to-eax
15065     # . epilogue
15066     89/<- %esp 5/r32/ebp
15067     5d/pop-to-ebp
15068     c3/return
15069 
15070 is-mu-branch?:  # stmt: (addr stmt1) -> result/eax: boolean
15071     # . prologue
15072     55/push-ebp
15073     89/<- %ebp 4/r32/esp
15074     # . save registers
15075     51/push-ecx
15076     # ecx = lookup(stmt->operation)
15077     8b/-> *(ebp+8) 1/r32/ecx
15078     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
15079     89/<- %ecx 0/r32/eax
15080     # if (stmt->operation starts with "loop") return true
15081     (string-starts-with? %ecx "loop")  # => eax
15082     3d/compare-eax-and 0/imm32/false
15083     75/jump-if-not-equal $is-mu-branch?:end/disp8
15084     # otherwise return (stmt->operation starts with "break")
15085     (string-starts-with? %ecx "break")  # => eax
15086 $is-mu-branch?:end:
15087     # . restore registers
15088     59/pop-to-ecx
15089     # . epilogue
15090     89/<- %esp 5/r32/ebp
15091     5d/pop-to-ebp
15092     c3/return
15093 
15094 emit-reverse-break:  # out: (addr buffered-file), stmt: (addr stmt1)
15095     # . prologue
15096     55/push-ebp
15097     89/<- %ebp 4/r32/esp
15098     # . save registers
15099     50/push-eax
15100     # eax = stmt
15101     8b/-> *(ebp+0xc) 0/r32/eax
15102     #
15103     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
15104     (get Reverse-branch %eax 0x10 "reverse-branch: ")  # => eax: (addr handle array byte)
15105     (emit-indent *(ebp+8) *Curr-block-depth)
15106     (lookup *eax *(eax+4))  # => eax
15107     (write-buffered *(ebp+8) %eax)
15108     (write-buffered *(ebp+8) " break/disp32\n")
15109 $emit-reverse-break:end:
15110     # . restore registers
15111     58/pop-to-eax
15112     # . epilogue
15113     89/<- %esp 5/r32/ebp
15114     5d/pop-to-ebp
15115     c3/return
15116 
15117 == data
15118 
15119 # Table from Mu branch instructions to the reverse SubX opcodes for them.
15120 Reverse-branch:  # (table (handle array byte) (handle array byte))
15121   # a table is a stream
15122   0x140/imm32/write
15123   0/imm32/read
15124   0x140/imm32/size
15125   # data
15126   0x11/imm32/alloc-id   _string-break-if-=/imm32                0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
15127   0x11/imm32/alloc-id   _string-loop-if-=/imm32                 0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
15128   0x11/imm32/alloc-id   _string-break-if-!=/imm32               0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
15129   0x11/imm32/alloc-id   _string-loop-if-!=/imm32                0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
15130   0x11/imm32/alloc-id   _string-break-if-</imm32                0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
15131   0x11/imm32/alloc-id   _string-loop-if-</imm32                 0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
15132   0x11/imm32/alloc-id   _string-break-if->/imm32                0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
15133   0x11/imm32/alloc-id   _string-loop-if->/imm32                 0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
15134   0x11/imm32/alloc-id   _string-break-if-<=/imm32               0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
15135   0x11/imm32/alloc-id   _string-loop-if-<=/imm32                0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
15136   0x11/imm32/alloc-id   _string-break-if->=/imm32               0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
15137   0x11/imm32/alloc-id   _string-loop-if->=/imm32                0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
15138   0x11/imm32/alloc-id   _string-break-if-addr</imm32            0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
15139   0x11/imm32/alloc-id   _string-loop-if-addr</imm32             0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
15140   0x11/imm32/alloc-id   _string-break-if-addr>/imm32            0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
15141   0x11/imm32/alloc-id   _string-loop-if-addr>/imm32             0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
15142   0x11/imm32/alloc-id   _string-break-if-addr<=/imm32           0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
15143   0x11/imm32/alloc-id   _string-loop-if-addr<=/imm32            0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
15144   0x11/imm32/alloc-id   _string-break-if-addr>=/imm32           0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
15145   0x11/imm32/alloc-id   _string-loop-if-addr>=/imm32            0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
15146 
15147 == code
15148 
15149 emit-unconditional-jump-to-depth:  # out: (addr buffered-file), vars: (addr stack live-var), depth: int, label-suffix: (addr array byte)
15150     # . prologue
15151     55/push-ebp
15152     89/<- %ebp 4/r32/esp
15153     # . save registers
15154     50/push-eax
15155     51/push-ecx
15156     52/push-edx
15157     53/push-ebx
15158     56/push-esi
15159     # ecx = vars
15160     8b/-> *(ebp+0xc) 1/r32/ecx
15161     # var eax: int = vars->top
15162     8b/-> *ecx 0/r32/eax
15163     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
15164     8d/copy-address *(ecx+eax-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
15165     # var min/ecx: (addr handle var) = vars->data
15166     8d/copy-address *(ecx+8) 1/r32/ecx
15167     # edx = depth
15168     8b/-> *(ebp+0x10) 2/r32/edx
15169     {
15170 $emit-unconditional-jump-to-depth:loop:
15171       # if (curr < min) break
15172       39/compare %esi 1/r32/ecx
15173       0f 82/jump-if-addr< break/disp32
15174       # var v/ebx: (addr var) = lookup(*curr)
15175       (lookup *esi *(esi+4))  # => eax
15176       89/<- %ebx 0/r32/eax
15177       # if (v->block-depth < until-block-depth) break
15178       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
15179       0f 8c/jump-if-< break/disp32
15180       {
15181 $emit-unconditional-jump-to-depth:check:
15182         # if v->block-depth != until-block-depth, continue
15183         39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
15184         0f 85/jump-if-!= break/disp32
15185 $emit-unconditional-jump-to-depth:depth-found:
15186         # if v is not a literal, continue
15187         (size-of %ebx)  # => eax
15188         3d/compare-eax-and 0/imm32
15189         0f 85/jump-if-!= break/disp32
15190 $emit-unconditional-jump-to-depth:label-found:
15191         # emit unconditional jump, then return
15192         (emit-indent *(ebp+8) *Curr-block-depth)
15193         (write-buffered *(ebp+8) "e9/jump ")
15194         (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
15195         (write-buffered *(ebp+8) %eax)
15196         (write-buffered *(ebp+8) ":")
15197         (write-buffered *(ebp+8) *(ebp+0x14))
15198         (write-buffered *(ebp+8) "/disp32\n")
15199         eb/jump $emit-unconditional-jump-to-depth:end/disp8
15200       }
15201       # curr -= 12
15202       81 5/subop/subtract %esi 0xc/imm32
15203       e9/jump loop/disp32
15204     }
15205     # TODO: error if no label at 'depth' was found
15206 $emit-unconditional-jump-to-depth:end:
15207     # . restore registers
15208     5e/pop-to-esi
15209     5b/pop-to-ebx
15210     5a/pop-to-edx
15211     59/pop-to-ecx
15212     58/pop-to-eax
15213     # . epilogue
15214     89/<- %esp 5/r32/ebp
15215     5d/pop-to-ebp
15216     c3/return
15217 
15218 # emit clean-up code for 'vars' until some block depth
15219 # doesn't actually modify 'vars' so we need traverse manually inside the stack
15220 emit-cleanup-code-until-depth:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-depth: int
15221     # . prologue
15222     55/push-ebp
15223     89/<- %ebp 4/r32/esp
15224     # . save registers
15225     50/push-eax
15226     51/push-ecx
15227     52/push-edx
15228     53/push-ebx
15229     56/push-esi
15230 #?     (write-buffered Stderr "--- cleanup\n")
15231 #?     (flush Stderr)
15232     # ecx = vars
15233     8b/-> *(ebp+0xc) 1/r32/ecx
15234     # var esi: int = vars->top
15235     8b/-> *ecx 6/r32/esi
15236     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
15237     8d/copy-address *(ecx+esi-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
15238     # var min/ecx: (addr handle var) = vars->data
15239     81 0/subop/add %ecx 8/imm32
15240     # edx = until-block-depth
15241     8b/-> *(ebp+0x10) 2/r32/edx
15242     {
15243 $emit-cleanup-code-until-depth:loop:
15244       # if (curr < min) break
15245       39/compare %esi 1/r32/ecx
15246       0f 82/jump-if-addr< break/disp32
15247       # var v/ebx: (addr var) = lookup(*curr)
15248       (lookup *esi *(esi+4))  # => eax
15249       89/<- %ebx 0/r32/eax
15250 #?       (lookup *ebx *(ebx+4))  # Var-name
15251 #?       (write-buffered Stderr "var ")
15252 #?       (write-buffered Stderr %eax)
15253 #?       (write-buffered Stderr Newline)
15254 #?       (flush Stderr)
15255       # if (v->block-depth < until-block-depth) break
15256       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
15257       0f 8c/jump-if-< break/disp32
15258       # if v is in a register
15259       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
15260       {
15261         0f 84/jump-if-= break/disp32
15262         {
15263 $emit-cleanup-code-until-depth:check-for-previous-spill:
15264           8b/-> *(esi+8) 0/r32/eax  # Live-var-register-spilled
15265           3d/compare-eax-and 0/imm32/false
15266           74/jump-if-= break/disp8
15267 $emit-cleanup-code-until-depth:reclaim-var-in-register:
15268           (emit-indent *(ebp+8) *Curr-block-depth)
15269           (write-buffered *(ebp+8) "8f 0/subop/pop %")
15270           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
15271           (write-buffered *(ebp+8) %eax)
15272           (write-buffered *(ebp+8) Newline)
15273         }
15274         eb/jump $emit-cleanup-code-until-depth:continue/disp8
15275       }
15276       # otherwise v is on the stack
15277       {
15278         75/jump-if-!= break/disp8
15279 $emit-cleanup-code-until-depth:var-on-stack:
15280         (size-of %ebx)  # => eax
15281         # don't emit code for labels
15282         3d/compare-eax-and 0/imm32
15283         74/jump-if-= break/disp8
15284 $emit-cleanup-code-until-depth:reclaim-var-on-stack:
15285         (emit-indent *(ebp+8) *Curr-block-depth)
15286         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
15287         (write-int32-hex-buffered *(ebp+8) %eax)
15288         (write-buffered *(ebp+8) "/imm32\n")
15289       }
15290 $emit-cleanup-code-until-depth:continue:
15291       # curr -= 12
15292       81 5/subop/subtract %esi 0xc/imm32
15293       e9/jump loop/disp32
15294     }
15295 $emit-cleanup-code-until-depth:end:
15296     # . restore registers
15297     5e/pop-to-esi
15298     5b/pop-to-ebx
15299     5a/pop-to-edx
15300     59/pop-to-ecx
15301     58/pop-to-eax
15302     # . epilogue
15303     89/<- %esp 5/r32/ebp
15304     5d/pop-to-ebp
15305     c3/return
15306 
15307 # emit clean-up code for 'vars' until a given label is encountered
15308 # doesn't actually modify 'vars' so we need traverse manually inside the stack
15309 emit-cleanup-code-until-target:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-label: (addr array byte)
15310     # . prologue
15311     55/push-ebp
15312     89/<- %ebp 4/r32/esp
15313     # . save registers
15314     50/push-eax
15315     51/push-ecx
15316     52/push-edx
15317     53/push-ebx
15318     # ecx = vars
15319     8b/-> *(ebp+0xc) 1/r32/ecx
15320     # var eax: int = vars->top
15321     8b/-> *ecx 0/r32/eax
15322     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
15323     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
15324     # var min/ecx: (addr handle var) = vars->data
15325     81 0/subop/add %ecx 8/imm32
15326     {
15327 $emit-cleanup-code-until-target:loop:
15328       # if (curr < min) break
15329       39/compare %edx 1/r32/ecx
15330       0f 82/jump-if-addr< break/disp32
15331       # var v/ebx: (handle var) = lookup(*curr)
15332       (lookup *edx *(edx+4))  # => eax
15333       89/<- %ebx 0/r32/eax
15334       # if (v->name == until-block-label) break
15335       (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
15336       (string-equal? %eax *(ebp+0x10))  # => eax
15337       3d/compare-eax-and 0/imm32/false
15338       0f 85/jump-if-!= break/disp32
15339       # if v is in a register
15340       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
15341       {
15342         0f 84/jump-if-= break/disp32
15343         {
15344 $emit-cleanup-code-until-target:check-for-previous-spill:
15345           8b/-> *(edx+8) 0/r32/eax  # Live-var-register-spilled
15346           3d/compare-eax-and 0/imm32/false
15347           74/jump-if-= break/disp8
15348 $emit-cleanup-code-until-target:reclaim-var-in-register:
15349           (emit-indent *(ebp+8) *Curr-block-depth)
15350           (write-buffered *(ebp+8) "8f 0/subop/pop %")
15351           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
15352           (write-buffered *(ebp+8) %eax)
15353           (write-buffered *(ebp+8) Newline)
15354         }
15355         eb/jump $emit-cleanup-code-until-target:continue/disp8
15356       }
15357       # otherwise v is on the stack
15358       {
15359         75/jump-if-!= break/disp8
15360 $emit-cleanup-code-until-target:reclaim-var-on-stack:
15361         (size-of %ebx)  # => eax
15362         # don't emit code for labels
15363         3d/compare-eax-and 0/imm32
15364         74/jump-if-= break/disp8
15365         #
15366         (emit-indent *(ebp+8) *Curr-block-depth)
15367         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
15368         (write-int32-hex-buffered *(ebp+8) %eax)
15369         (write-buffered *(ebp+8) "/imm32\n")
15370       }
15371 $emit-cleanup-code-until-target:continue:
15372       # curr -= 12
15373       81 5/subop/subtract %edx 0xc/imm32
15374       e9/jump loop/disp32
15375     }
15376 $emit-cleanup-code-until-target:end:
15377     # . restore registers
15378     5b/pop-to-ebx
15379     5a/pop-to-edx
15380     59/pop-to-ecx
15381     58/pop-to-eax
15382     # . epilogue
15383     89/<- %esp 5/r32/ebp
15384     5d/pop-to-ebp
15385     c3/return
15386 
15387 # Return true if there isn't a variable in 'vars' with the same block-depth
15388 # and register as 'v'.
15389 # 'v' is guaranteed not to be within 'vars'.
15390 not-yet-spilled-this-block?:  # v: (addr var), vars: (addr stack live-var) -> result/eax: boolean
15391     # . prologue
15392     55/push-ebp
15393     89/<- %ebp 4/r32/esp
15394     # . save registers
15395     51/push-ecx
15396     52/push-edx
15397     53/push-ebx
15398     56/push-esi
15399     57/push-edi
15400     # ecx = vars
15401     8b/-> *(ebp+0xc) 1/r32/ecx
15402     # var eax: int = vars->top
15403     8b/-> *ecx 0/r32/eax
15404     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
15405     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
15406     # var min/ecx: (addr handle var) = vars->data
15407     8d/copy-address *(ecx+8) 1/r32/ecx
15408     # var depth/ebx: int = v->block-depth
15409     8b/-> *(ebp+8) 3/r32/ebx
15410     8b/-> *(ebx+0x10) 3/r32/ebx  # Var-block-depth
15411     # var needle/esi: (addr array byte) = v->register
15412     8b/-> *(ebp+8) 6/r32/esi
15413     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
15414     89/<- %esi 0/r32/eax
15415     {
15416 $not-yet-spilled-this-block?:loop:
15417       # if (curr < min) break
15418       39/compare %edx 1/r32/ecx
15419       0f 82/jump-if-addr< break/disp32
15420       # var cand/edi: (addr var) = lookup(*curr)
15421       (lookup *edx *(edx+4))  # => eax
15422       89/<- %edi 0/r32/eax
15423       # if (cand->block-depth < depth) break
15424       39/compare *(edi+0x10) 3/r32/ebx  # Var-block-depth
15425       0f 8c/jump-if-< break/disp32
15426       # var cand-reg/edi: (array array byte) = cand->reg
15427       (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
15428       89/<- %edi 0/r32/eax
15429       # if (cand-reg == null) continue
15430       {
15431 $not-yet-spilled-this-block?:check-reg:
15432         81 7/subop/compare %edi 0/imm32
15433         0f 84/jump-if-= break/disp32
15434         # if (cand-reg == needle) return true
15435         (string-equal? %esi %edi)  # => eax
15436         3d/compare-eax-and 0/imm32/false
15437         74/jump-if-= break/disp8
15438 $not-yet-spilled-this-block?:return-false:
15439         b8/copy-to-eax 0/imm32/false
15440         eb/jump $not-yet-spilled-this-block?:end/disp8
15441       }
15442 $not-yet-spilled-this-block?:continue:
15443       # curr -= 12
15444       81 5/subop/subtract %edx 0xc/imm32
15445       e9/jump loop/disp32
15446     }
15447 $not-yet-spilled-this-block?:return-true:
15448     # return true
15449     b8/copy-to-eax 1/imm32/true
15450 $not-yet-spilled-this-block?:end:
15451     # . restore registers
15452     5f/pop-to-edi
15453     5e/pop-to-esi
15454     5b/pop-to-ebx
15455     5a/pop-to-edx
15456     59/pop-to-ecx
15457     # . epilogue
15458     89/<- %esp 5/r32/ebp
15459     5d/pop-to-ebp
15460     c3/return
15461 
15462 # could the register of 'v' ever be written to by one of the vars in fn-outputs?
15463 will-not-write-some-register?:  # v: (addr var), stmts: (addr list stmt), fn: (addr function) -> result/eax: boolean
15464     # . prologue
15465     55/push-ebp
15466     89/<- %ebp 4/r32/esp
15467     # eax = v
15468     8b/-> *(ebp+8) 0/r32/eax
15469     # var reg/eax: (addr array byte) = lookup(v->register)
15470     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15471     # var target/eax: (addr var) = find-register(fn-outputs, reg)
15472     (find-register *(ebp+0x10) %eax)  # => eax
15473     # if (target == 0) return true
15474     {
15475       3d/compare-eax-and 0/imm32
15476       75/jump-if-!= break/disp8
15477       b8/copy-to-eax 1/imm32/true
15478       eb/jump $will-not-write-some-register?:end/disp8
15479     }
15480     # return !assigns-in-stmts?(stmts, target)
15481     (assigns-in-stmts? *(ebp+0xc) %eax)  # => eax
15482     3d/compare-eax-and 0/imm32/false
15483     # assume: true = 1, so no need to mask with 0x000000ff
15484     0f 94/set-if-= %al
15485 $will-not-write-some-register?:end:
15486     # . epilogue
15487     89/<- %esp 5/r32/ebp
15488     5d/pop-to-ebp
15489     c3/return
15490 
15491 # return fn output with matching register
15492 # always returns false if 'reg' is null
15493 find-register:  # fn: (addr function), reg: (addr array byte) -> result/eax: (addr var)
15494     # . prologue
15495     55/push-ebp
15496     89/<- %ebp 4/r32/esp
15497     # . save registers
15498     51/push-ecx
15499     # var curr/ecx: (addr list var) = lookup(fn->outputs)
15500     8b/-> *(ebp+8) 1/r32/ecx
15501     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
15502     89/<- %ecx 0/r32/eax
15503     {
15504 $find-register:loop:
15505       # if (curr == 0) break
15506       81 7/subop/compare %ecx 0/imm32
15507       74/jump-if-= break/disp8
15508       # eax = curr->value->register
15509       (lookup *ecx *(ecx+4))  # List-value List-value => eax
15510       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15511       # if (eax == reg) return curr->value
15512 $find-register:compare:
15513       (string-equal? *(ebp+0xc) %eax)  # => eax
15514       {
15515         3d/compare-eax-and 0/imm32/false
15516         74/jump-if-= break/disp8
15517 $find-register:found:
15518         (lookup *ecx *(ecx+4))  # List-value List-value => eax
15519         eb/jump $find-register:end/disp8
15520       }
15521       # curr = lookup(curr->next)
15522       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
15523       89/<- %ecx 0/r32/eax
15524       #
15525       eb/jump loop/disp8
15526     }
15527 $find-register:end:
15528     # . restore registers
15529     59/pop-to-ecx
15530     # . epilogue
15531     89/<- %esp 5/r32/ebp
15532     5d/pop-to-ebp
15533     c3/return
15534 
15535 assigns-in-stmts?:  # stmts: (addr list stmt), v: (addr var) -> result/eax: boolean
15536     # . prologue
15537     55/push-ebp
15538     89/<- %ebp 4/r32/esp
15539     # . save registers
15540     51/push-ecx
15541     # var curr/ecx: (addr list stmt) = stmts
15542     8b/-> *(ebp+8) 1/r32/ecx
15543     {
15544       # if (curr == 0) break
15545       81 7/subop/compare %ecx 0/imm32
15546       74/jump-if-= break/disp8
15547       # if assigns-in-stmt?(curr->value, v) return true
15548       (lookup *ecx *(ecx+4))  # List-value List-value => eax
15549       (assigns-in-stmt? %eax *(ebp+0xc))  # => eax
15550       3d/compare-eax-and 0/imm32/false
15551       75/jump-if-!= break/disp8
15552       # curr = lookup(curr->next)
15553       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
15554       89/<- %ecx 0/r32/eax
15555       #
15556       eb/jump loop/disp8
15557     }
15558 $assigns-in-stmts?:end:
15559     # . restore registers
15560     59/pop-to-ecx
15561     # . epilogue
15562     89/<- %esp 5/r32/ebp
15563     5d/pop-to-ebp
15564     c3/return
15565 
15566 assigns-in-stmt?:  # stmt: (addr stmt), v: (addr var) -> result/eax: boolean
15567     # . prologue
15568     55/push-ebp
15569     89/<- %ebp 4/r32/esp
15570     # . save registers
15571     51/push-ecx
15572     # ecx = stmt
15573     8b/-> *(ebp+8) 1/r32/ecx
15574     # if stmt is a stmt1, return assigns-in-stmt-vars?(stmt->outputs, v)
15575     {
15576       81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
15577       75/jump-if-!= break/disp8
15578       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
15579       (assigns-in-stmt-vars? %eax *(ebp+0xc))  # => eax
15580       eb/jump $assigns-in-stmt?:end/disp8
15581     }
15582     # if stmt is a block, return assigns-in-stmts?(stmt->stmts, v)
15583     {
15584       81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
15585       75/jump-if-!= break/disp8
15586       (lookup *(ecx+4) *(ecx+8))  # Block-stmts Block-stmts => eax
15587       (assigns-in-stmts? %eax *(ebp+0xc))  # => eax
15588       eb/jump $assigns-in-stmt?:end/disp8
15589     }
15590     # otherwise return false
15591     b8/copy 0/imm32/false
15592 $assigns-in-stmt?:end:
15593     # . restore registers
15594     59/pop-to-ecx
15595     # . epilogue
15596     89/<- %esp 5/r32/ebp
15597     5d/pop-to-ebp
15598     c3/return
15599 
15600 assigns-in-stmt-vars?:  # stmt-var: (addr stmt-var), v: (addr var) -> result/eax: boolean
15601     # . prologue
15602     55/push-ebp
15603     89/<- %ebp 4/r32/esp
15604     # . save registers
15605     51/push-ecx
15606     # var curr/ecx: (addr stmt-var) = stmt-var
15607     8b/-> *(ebp+8) 1/r32/ecx
15608     {
15609       # if (curr == 0) break
15610       81 7/subop/compare %ecx 0/imm32
15611       74/jump-if-= break/disp8
15612       # eax = lookup(curr->value)
15613       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
15614       # if (eax == v  &&  curr->is-deref? == false) return true
15615       {
15616         39/compare *(ebp+0xc) 0/r32/eax
15617         75/jump-if-!= break/disp8
15618         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
15619         75/jump-if-!= break/disp8
15620         b8/copy-to-eax 1/imm32/true
15621         eb/jump $assigns-in-stmt-vars?:end/disp8
15622       }
15623       # curr = lookup(curr->next)
15624       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
15625       89/<- %ecx 0/r32/eax
15626       #
15627       eb/jump loop/disp8
15628     }
15629 $assigns-in-stmt-vars?:end:
15630     # . restore registers
15631     59/pop-to-ecx
15632     # . epilogue
15633     89/<- %esp 5/r32/ebp
15634     5d/pop-to-ebp
15635     c3/return
15636 
15637 # is there a var before 'v' with the same block-depth and register on the 'vars' stack?
15638 # v is guaranteed to be within vars
15639 # 'start' is provided as an optimization, a pointer within vars
15640 # *start == v
15641 same-register-spilled-before?:  # v: (addr var), vars: (addr stack (handle var)), start: (addr var) -> result/eax: boolean
15642     # . prologue
15643     55/push-ebp
15644     89/<- %ebp 4/r32/esp
15645     # . save registers
15646     51/push-ecx
15647     52/push-edx
15648     53/push-ebx
15649     56/push-esi
15650     57/push-edi
15651     # ecx = v
15652     8b/-> *(ebp+8) 1/r32/ecx
15653     # var reg/edx: (addr array byte) = lookup(v->register)
15654     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
15655     89/<- %edx 0/r32/eax
15656     # var depth/ebx: int = v->block-depth
15657     8b/-> *(ecx+0x10) 3/r32/ebx  # Var-block-depth
15658     # var min/ecx: (addr handle var) = vars->data
15659     8b/-> *(ebp+0xc) 1/r32/ecx
15660     81 0/subop/add %ecx 8/imm32
15661     # TODO: check that start >= min and start < &vars->data[top]
15662     # TODO: check that *start == v
15663     # var curr/esi: (addr handle var) = start
15664     8b/-> *(ebp+0x10) 6/r32/esi
15665     # curr -= 8
15666     81 5/subop/subtract %esi 8/imm32
15667     {
15668 $same-register-spilled-before?:loop:
15669       # if (curr < min) break
15670       39/compare %esi 1/r32/ecx
15671       0f 82/jump-if-addr< break/disp32
15672       # var x/eax: (addr var) = lookup(*curr)
15673       (lookup *esi *(esi+4))  # => eax
15674       # if (x->block-depth < depth) break
15675       39/compare *(eax+0x10) 3/r32/ebx  # Var-block-depth
15676       0f 8c/jump-if-< break/disp32
15677       # if (x->register == 0) continue
15678       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
15679       74/jump-if-= $same-register-spilled-before?:continue/disp8
15680       # if (x->register == reg) return true
15681       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15682       (string-equal? %eax %edx)  # => eax
15683       3d/compare-eax-and 0/imm32/false
15684       b8/copy-to-eax 1/imm32/true
15685       75/jump-if-!= $same-register-spilled-before?:end/disp8
15686 $same-register-spilled-before?:continue:
15687       # curr -= 8
15688       81 5/subop/subtract %esi 8/imm32
15689       e9/jump loop/disp32
15690     }
15691 $same-register-spilled-before?:false:
15692     b8/copy-to-eax 0/imm32/false
15693 $same-register-spilled-before?:end:
15694     # . restore registers
15695     5f/pop-to-edi
15696     5e/pop-to-esi
15697     5b/pop-to-ebx
15698     5a/pop-to-edx
15699     59/pop-to-ecx
15700     # . epilogue
15701     89/<- %esp 5/r32/ebp
15702     5d/pop-to-ebp
15703     c3/return
15704 
15705 # Clean up global state for 'vars' until some block depth (inclusive).
15706 #
15707 # This would be a simple series of pops, if it wasn't for fn outputs, which
15708 # can occur anywhere in the stack.
15709 # So we have to _compact_ the entire array underlying the stack.
15710 #
15711 # We want to allow a fn output register to be written to by locals before the
15712 # output is set.
15713 # So fn outputs can't just be pushed at the start of the function.
15714 #
15715 # We want to allow other locals to shadow a fn output register after the
15716 # output is set.
15717 # So the output can't just always override anything in the stack. Sequence matters.
15718 clean-up-blocks:  # vars: (addr stack live-var), until-block-depth: int, fn: (addr function)
15719     # pseudocode:
15720     #   to = vars->top  (which points outside the stack)
15721     #   while true
15722     #     if to <= 0
15723     #       break
15724     #     var v = vars->data[to-1]
15725     #     if v.depth < until and !in-function-outputs?(fn, v)
15726     #       break
15727     #     --to
15728     #   from = to
15729     #   while true
15730     #     if from >= vars->top
15731     #       break
15732     #     assert(from >= to)
15733     #     v = vars->data[from]
15734     #     if in-function-outputs?(fn, v)
15735     #       if from > to
15736     #         vars->data[to] = vars->data[from]
15737     #       ++to
15738     #     ++from
15739     #   vars->top = to
15740     #
15741     # . prologue
15742     55/push-ebp
15743     89/<- %ebp 4/r32/esp
15744     # . save registers
15745     50/push-eax
15746     52/push-edx
15747     53/push-ebx
15748     56/push-esi
15749     57/push-edi
15750     # ebx = vars
15751     8b/-> *(ebp+8) 3/r32/ebx
15752     # edx = until-block-depth
15753     8b/-> *(ebp+0xc) 2/r32/edx
15754 $clean-up-blocks:phase1:
15755     # var to/edi: int = vars->top
15756     8b/-> *ebx 7/r32/edi
15757     {
15758 $clean-up-blocks:loop1:
15759       # if (to <= 0) break
15760       81 7/subop/compare %edi 0/imm32
15761       7e/jump-if-<= break/disp8
15762       # var v/eax: (addr var) = lookup(vars->data[to-1]->var)
15763       8d/copy-address *(ebx+edi-4) 0/r32/eax  # vars + 8 + to - 12
15764       (lookup *eax *(eax+4))  # => eax
15765       # if (v->block-depth >= until-block-depth) continue
15766       39/compare *(eax+0x10) 2/r32/edx  # Var-block-depth
15767       {
15768         7d/jump-if->= break/disp8
15769         # if (!in-function-outputs?(fn, v)) break
15770         (in-function-outputs? *(ebp+0x10) %eax)  # => eax
15771         3d/compare-eax-and 0/imm32/false
15772         74/jump-if-= $clean-up-blocks:phase2/disp8
15773       }
15774 $clean-up-blocks:loop1-continue:
15775       # --to
15776       81 5/subop/subtract %edi 0xc/imm32
15777       #
15778       eb/jump loop/disp8
15779     }
15780 $clean-up-blocks:phase2:
15781     # var from/esi: int = to
15782     89/<- %esi 7/r32/edi
15783     {
15784 $clean-up-blocks:loop2:
15785       # if (from >= vars->top) break
15786       3b/compare 6/r32/esi *ebx
15787       7d/jump-if->= break/disp8
15788       # var v/eax: (addr var) = lookup(vars->data[from]->var)
15789       8d/copy-address *(ebx+esi+8) 0/r32/eax
15790       (lookup *eax *(eax+4))  # => eax
15791       # if !in-function-outputs?(fn, v) continue
15792       (in-function-outputs? *(ebp+0x10) %eax)  # => eax
15793       3d/compare-eax-and 0/imm32/false
15794       74/jump-if-= $clean-up-blocks:loop2-continue/disp8
15795       # invariant: from >= to
15796       # if (from > to) vars->data[to] = vars->data[from]
15797       {
15798         39/compare %esi 7/r32/edi
15799         7e/jump-if-<= break/disp8
15800         56/push-esi
15801         57/push-edi
15802         # . var from/esi: (addr byte) = &vars->data[from]
15803         8d/copy-address *(ebx+esi+8) 6/r32/esi
15804         # . var to/edi: (addr byte) = &vars->data[to]
15805         8d/copy-address *(ebx+edi+8) 7/r32/edi
15806         # .
15807         8b/-> *esi 0/r32/eax
15808         89/<- *edi 0/r32/eax
15809         8b/-> *(esi+4) 0/r32/eax
15810         89/<- *(edi+4) 0/r32/eax
15811         8b/-> *(esi+8) 0/r32/eax
15812         89/<- *(edi+8) 0/r32/eax
15813         5f/pop-to-edi
15814         5e/pop-to-esi
15815       }
15816       # ++to
15817       81 0/subop/add %edi 0xc/imm32
15818 $clean-up-blocks:loop2-continue:
15819       # ++from
15820       81 0/subop/add %esi 0xc/imm32
15821       #
15822       eb/jump loop/disp8
15823     }
15824     89/<- *ebx 7/r32/edi
15825 $clean-up-blocks:end:
15826     # . restore registers
15827     5f/pop-to-edi
15828     5e/pop-to-esi
15829     5b/pop-to-ebx
15830     5a/pop-to-edx
15831     58/pop-to-eax
15832     # . epilogue
15833     89/<- %esp 5/r32/ebp
15834     5d/pop-to-ebp
15835     c3/return
15836 
15837 in-function-outputs?:  # fn: (addr function), target: (addr var) -> result/eax: boolean
15838     # . prologue
15839     55/push-ebp
15840     89/<- %ebp 4/r32/esp
15841     # . save registers
15842     51/push-ecx
15843     # var curr/ecx: (addr list var) = lookup(fn->outputs)
15844     8b/-> *(ebp+8) 1/r32/ecx
15845     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
15846     89/<- %ecx 0/r32/eax
15847     # while curr != null
15848     {
15849       81 7/subop/compare %ecx 0/imm32
15850       74/jump-if-= break/disp8
15851       # var v/eax: (addr var) = lookup(curr->value)
15852       (lookup *ecx *(ecx+4))  # List-value List-value => eax
15853       # if (v == target) return true
15854       39/compare *(ebp+0xc) 0/r32/eax
15855       b8/copy-to-eax 1/imm32/true
15856       74/jump-if-= $in-function-outputs?:end/disp8
15857       # curr = curr->next
15858       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
15859       89/<- %ecx 0/r32/eax
15860       #
15861       eb/jump loop/disp8
15862     }
15863     b8/copy-to-eax 0/imm32
15864 $in-function-outputs?:end:
15865     # . restore registers
15866     59/pop-to-ecx
15867     # . epilogue
15868     89/<- %esp 5/r32/ebp
15869     5d/pop-to-ebp
15870     c3/return
15871 
15872 emit-subx-var-def:  # out: (addr buffered-file), stmt: (addr stmt)
15873     # . prologue
15874     55/push-ebp
15875     89/<- %ebp 4/r32/esp
15876     # . save registers
15877     50/push-eax
15878     51/push-ecx
15879     52/push-edx
15880     # eax = stmt
15881     8b/-> *(ebp+0xc) 0/r32/eax
15882     # var v/ecx: (addr var)
15883     (lookup *(eax+4) *(eax+8))  # Vardef-var Vardef-var => eax
15884     89/<- %ecx 0/r32/eax
15885     # v->block-depth = *Curr-block-depth
15886     8b/-> *Curr-block-depth 0/r32/eax
15887     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
15888     # var n/edx: int = size-of(stmt->var)
15889     (size-of %ecx)  # => eax
15890     89/<- %edx 0/r32/eax
15891     # *Curr-local-stack-offset -= n
15892     29/subtract-from *Curr-local-stack-offset 2/r32/edx
15893     # v->offset = *Curr-local-stack-offset
15894     8b/-> *Curr-local-stack-offset 0/r32/eax
15895     89/<- *(ecx+0x14) 0/r32/eax  # Var-offset
15896     # if v is an array, do something special to initialize it
15897     {
15898       (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
15899       (is-mu-array? %eax)  # => eax
15900       3d/compare-eax-and 0/imm32/false
15901       0f 84/jump-if-= break/disp32
15902       # var array-size-without-size/edx: int = n-4
15903       81 5/subop/subtract %edx 4/imm32
15904       #
15905       (emit-array-data-initialization *(ebp+8) %edx)
15906       e9/jump $emit-subx-var-def:end/disp32
15907     }
15908     # another special-case for initializing streams
15909     # a stream is an array with 2 extra pointers
15910     {
15911       (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
15912       (is-mu-stream? %eax)  # => eax
15913       3d/compare-eax-and 0/imm32/false
15914       0f 84/jump-if-= break/disp32
15915       # var array-size-without-size/edx: int = n-12
15916       81 5/subop/subtract %edx 0xc/imm32
15917       (emit-array-data-initialization *(ebp+8) %edx)
15918       # emit read and write pointers
15919       (emit-indent *(ebp+8) *Curr-block-depth)
15920       (write-buffered *(ebp+8) "68/push 0/imm32\n")
15921       (emit-indent *(ebp+8) *Curr-block-depth)
15922       (write-buffered *(ebp+8) "68/push 0/imm32\n")
15923       #
15924       eb/jump $emit-subx-var-def:end/disp8
15925     }
15926     # while n > 0
15927     {
15928       81 7/subop/compare %edx 0/imm32
15929       7e/jump-if-<= break/disp8
15930       (emit-indent *(ebp+8) *Curr-block-depth)
15931       (write-buffered *(ebp+8) "68/push 0/imm32\n")
15932       # n -= 4
15933       81 5/subop/subtract %edx 4/imm32
15934       #
15935       eb/jump loop/disp8
15936     }
15937 $emit-subx-var-def:end:
15938     # . restore registers
15939     5a/pop-to-edx
15940     59/pop-to-ecx
15941     58/pop-to-eax
15942     # . epilogue
15943     89/<- %esp 5/r32/ebp
15944     5d/pop-to-ebp
15945     c3/return
15946 
15947 emit-array-data-initialization:  # out: (addr buffered-file), n: int
15948     # . prologue
15949     55/push-ebp
15950     89/<- %ebp 4/r32/esp
15951     #
15952     (emit-indent *(ebp+8) *Curr-block-depth)
15953     (write-buffered *(ebp+8) "(push-n-zero-bytes ")
15954     (write-int32-hex-buffered *(ebp+8) *(ebp+0xc))
15955     (write-buffered *(ebp+8) ")\n")
15956     (emit-indent *(ebp+8) *Curr-block-depth)
15957     (write-buffered *(ebp+8) "68/push ")
15958     (write-int32-hex-buffered *(ebp+8) *(ebp+0xc))
15959     (write-buffered *(ebp+8) "/imm32\n")
15960 $emit-array-data-initialization:end:
15961     # . epilogue
15962     89/<- %esp 5/r32/ebp
15963     5d/pop-to-ebp
15964     c3/return
15965 
15966 emit-subx-stmt:  # out: (addr buffered-file), stmt: (addr stmt), primitives: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
15967     # . prologue
15968     55/push-ebp
15969     89/<- %ebp 4/r32/esp
15970     # . save registers
15971     50/push-eax
15972     51/push-ecx
15973     # - some special-case primitives that don't actually use the 'primitives' data structure
15974     # var op/ecx: (addr array byte) = lookup(stmt->operation)
15975     8b/-> *(ebp+0xc) 1/r32/ecx
15976     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
15977     89/<- %ecx 0/r32/eax
15978     # array size
15979     {
15980       # if (!string-equal?(stmt->operation, "length")) break
15981       (string-equal? %ecx "length")  # => eax
15982       3d/compare-eax-and 0/imm32
15983       0f 84/jump-if-= break/disp32
15984       (translate-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
15985       e9/jump $emit-subx-stmt:end/disp32
15986     }
15987     # index into array
15988     {
15989       # if (!string-equal?(stmt->operation, "index")) break
15990       (string-equal? %ecx "index")  # => eax
15991       3d/compare-eax-and 0/imm32
15992       0f 84/jump-if-= break/disp32
15993       (translate-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
15994       e9/jump $emit-subx-stmt:end/disp32
15995     }
15996     # compute-offset for index into array
15997     {
15998       # if (!string-equal?(stmt->operation, "compute-offset")) break
15999       (string-equal? %ecx "compute-offset")  # => eax
16000       3d/compare-eax-and 0/imm32
16001       0f 84/jump-if-= break/disp32
16002       (translate-mu-compute-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16003       e9/jump $emit-subx-stmt:end/disp32
16004     }
16005     # get field from record
16006     {
16007       # if (!string-equal?(stmt->operation, "get")) break
16008       (string-equal? %ecx "get")  # => eax
16009       3d/compare-eax-and 0/imm32
16010       0f 84/jump-if-= break/disp32
16011       (translate-mu-get-stmt *(ebp+8) *(ebp+0xc))
16012       e9/jump $emit-subx-stmt:end/disp32
16013     }
16014     # allocate scalar
16015     {
16016       # if (!string-equal?(stmt->operation, "allocate")) break
16017       (string-equal? %ecx "allocate")  # => eax
16018       3d/compare-eax-and 0/imm32
16019       0f 84/jump-if-= break/disp32
16020       (translate-mu-allocate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16021       e9/jump $emit-subx-stmt:end/disp32
16022     }
16023     # allocate array
16024     {
16025       # if (!string-equal?(stmt->operation, "populate")) break
16026       (string-equal? %ecx "populate")  # => eax
16027       3d/compare-eax-and 0/imm32
16028       0f 84/jump-if-= break/disp32
16029       (translate-mu-populate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16030       e9/jump $emit-subx-stmt:end/disp32
16031     }
16032     # allocate stream
16033     {
16034       # if (!string-equal?(stmt->operation, "populate-stream")) break
16035       (string-equal? %ecx "populate-stream")  # => eax
16036       3d/compare-eax-and 0/imm32
16037       0f 84/jump-if-= break/disp32
16038       (translate-mu-populate-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16039       e9/jump $emit-subx-stmt:end/disp32
16040     }
16041     # read from stream
16042     {
16043       # if (!string-equal?(stmt->operation, "read-from-stream")) break
16044       (string-equal? %ecx "read-from-stream")  # => eax
16045       3d/compare-eax-and 0/imm32
16046       0f 84/jump-if-= break/disp32
16047       (translate-mu-read-from-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16048       e9/jump $emit-subx-stmt:end/disp32
16049     }
16050     # write to stream
16051     {
16052       # if (!string-equal?(stmt->operation, "write-to-stream")) break
16053       (string-equal? %ecx "write-to-stream")  # => eax
16054       3d/compare-eax-and 0/imm32
16055       0f 84/jump-if-= break/disp32
16056       (translate-mu-write-to-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16057       e9/jump $emit-subx-stmt:end/disp32
16058     }
16059     # - if stmt matches a primitive, emit it
16060     {
16061 $emit-subx-stmt:check-for-primitive:
16062       # var curr/eax: (addr primitive)
16063       (find-matching-primitive *(ebp+0x10) *(ebp+0xc))  # primitives, stmt => eax
16064       3d/compare-eax-and 0/imm32
16065       74/jump-if-= break/disp8
16066 $emit-subx-stmt:primitive:
16067       (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax)  # out, stmt, curr
16068       e9/jump $emit-subx-stmt:end/disp32
16069     }
16070     # - otherwise emit a call
16071     # TODO: type-checking
16072 $emit-subx-stmt:call:
16073     (emit-call *(ebp+8) *(ebp+0xc))
16074 $emit-subx-stmt:end:
16075     # . restore registers
16076     59/pop-to-ecx
16077     58/pop-to-eax
16078     # . epilogue
16079     89/<- %esp 5/r32/ebp
16080     5d/pop-to-ebp
16081     c3/return
16082 
16083 translate-mu-length-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
16084     # . prologue
16085     55/push-ebp
16086     89/<- %ebp 4/r32/esp
16087     # . save registers
16088     50/push-eax
16089     51/push-ecx
16090     52/push-edx
16091     53/push-ebx
16092     56/push-esi
16093     # esi = stmt
16094     8b/-> *(ebp+0xc) 6/r32/esi
16095     # var base/ebx: (addr var) = stmt->inouts[0]->value
16096     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16097     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16098     89/<- %ebx 0/r32/eax
16099     # var elemsize/ecx: int = array-element-size(base)
16100     (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
16101     89/<- %ecx 0/r32/eax
16102     # var outreg/edx: (addr array byte) = stmt->outputs[0]->value->register
16103     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
16104     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16105     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
16106     89/<- %edx 0/r32/eax
16107     # if elemsize == 1
16108     {
16109       81 7/subop/compare %ecx 1/imm32
16110       75/jump-if-!= break/disp8
16111 $translate-mu-length-stmt:size-1:
16112       (emit-save-size-to *(ebp+8) %ebx %edx)
16113       e9/jump $translate-mu-length-stmt:end/disp32
16114     }
16115     # if elemsize is a power of 2 less than 256
16116     {
16117       (power-of-2? %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
16118       3d/compare-eax-and 0/imm32/false
16119       74/jump-if-= break/disp8
16120       81 7/subop/compare %ecx 0xff/imm32
16121       7f/jump-if-> break/disp8
16122 $translate-mu-length-stmt:size-power-of-2:
16123       (emit-save-size-to *(ebp+8) %ebx %edx)
16124       (emit-divide-by-shift-right *(ebp+8) %edx %ecx)
16125       e9/jump $translate-mu-length-stmt:end/disp32
16126     }
16127     # otherwise, the complex case
16128     # . emit register spills
16129     {
16130 $translate-mu-length-stmt:complex:
16131       (string-equal? %edx "eax")  # => eax
16132       3d/compare-eax-and 0/imm32/false
16133       75/break-if-!= break/disp8
16134       (emit-indent *(ebp+8) *Curr-block-depth)
16135       (write-buffered *(ebp+8) "50/push-eax\n")
16136     }
16137     {
16138       (string-equal? %edx "ecx")  # => eax
16139       3d/compare-eax-and 0/imm32/false
16140       75/break-if-!= break/disp8
16141       (emit-indent *(ebp+8) *Curr-block-depth)
16142       (write-buffered *(ebp+8) "51/push-ecx\n")
16143     }
16144     {
16145       (string-equal? %edx "edx")  # => eax
16146       3d/compare-eax-and 0/imm32/false
16147       75/break-if-!= break/disp8
16148       (emit-indent *(ebp+8) *Curr-block-depth)
16149       (write-buffered *(ebp+8) "52/push-edx\n")
16150     }
16151     # .
16152     (emit-save-size-to *(ebp+8) %ebx "eax")
16153     (emit-indent *(ebp+8) *Curr-block-depth)
16154     (write-buffered *(ebp+8) "31/xor %edx 2/r32/edx\n")
16155     (emit-indent *(ebp+8) *Curr-block-depth)
16156     (write-buffered *(ebp+8) "b9/copy-to-ecx ")
16157     (write-int32-hex-buffered *(ebp+8) %ecx)
16158     (write-buffered *(ebp+8) "/imm32\n")
16159     (emit-indent *(ebp+8) *Curr-block-depth)
16160     (write-buffered *(ebp+8) "f7 7/subop/idiv-eax-edx-by %ecx\n")
16161     {
16162       (string-equal? %edx "eax")  # => eax
16163       3d/compare-eax-and 0/imm32/false
16164       75/break-if-!= break/disp8
16165       (emit-indent *(ebp+8) *Curr-block-depth)
16166       (write-buffered *(ebp+8) "89/<- %")
16167       (write-buffered *(ebp+8) %edx)
16168       (write-buffered *(ebp+8) " 0/r32/eax\n")
16169     }
16170     # . emit register restores
16171     {
16172       (string-equal? %edx "edx")  # => eax
16173       3d/compare-eax-and 0/imm32/false
16174       75/break-if-!= break/disp8
16175       (emit-indent *(ebp+8) *Curr-block-depth)
16176       (write-buffered *(ebp+8) "5a/pop-to-edx\n")
16177     }
16178     {
16179       (string-equal? %edx "ecx")  # => eax
16180       3d/compare-eax-and 0/imm32/false
16181       75/break-if-!= break/disp8
16182       (emit-indent *(ebp+8) *Curr-block-depth)
16183       (write-buffered *(ebp+8) "59/pop-to-ecx\n")
16184     }
16185     {
16186       (string-equal? %edx "eax")  # => eax
16187       3d/compare-eax-and 0/imm32/false
16188       75/break-if-!= break/disp8
16189       (emit-indent *(ebp+8) *Curr-block-depth)
16190       (write-buffered *(ebp+8) "58/pop-to-eax\n")
16191     }
16192 $translate-mu-length-stmt:end:
16193     # . restore registers
16194     5e/pop-to-esi
16195     5b/pop-to-ebx
16196     5a/pop-to-edx
16197     59/pop-to-ecx
16198     58/pop-to-eax
16199     # . epilogue
16200     89/<- %esp 5/r32/ebp
16201     5d/pop-to-ebp
16202     c3/return
16203 
16204 array-element-size:  # arr: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
16205     # . prologue
16206     55/push-ebp
16207     89/<- %ebp 4/r32/esp
16208     #
16209     (array-element-type-id *(ebp+8) *(ebp+0xc) *(ebp+0x10))  # => eax
16210     (size-of-type-id-as-array-element %eax)  # => eax
16211 $array-element-size:end:
16212     # . epilogue
16213     89/<- %esp 5/r32/ebp
16214     5d/pop-to-ebp
16215     c3/return
16216 
16217 array-element-type-id:  # v: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: type-id
16218     # precondition: n is positive
16219     # . prologue
16220     55/push-ebp
16221     89/<- %ebp 4/r32/esp
16222     #
16223     8b/-> *(ebp+8) 0/r32/eax
16224     # var t/eax: (addr type-tree)
16225     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
16226     # if t == 0 abort
16227     3d/compare-eax-with 0/imm32
16228     0f 84/jump-if-== $array-element-type-id:error0/disp32
16229     # if t->is-atom? abort
16230     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
16231     0f 85/jump-if-!= $array-element-type-id:error1/disp32
16232     # if (t->left == addr) t = t->right
16233     {
16234       50/push-eax
16235       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
16236       (is-simple-mu-type? %eax 2)  # addr => eax
16237       3d/compare-eax-with 0/imm32/false
16238       58/pop-to-eax
16239       74/jump-if-= break/disp8
16240 $array-element-type-id:skip-addr:
16241       (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
16242     }
16243     # if t == 0 abort
16244     3d/compare-eax-with 0/imm32
16245     0f 84/jump-if-= $array-element-type-id:error2/disp32
16246     # if t->is-atom? abort
16247     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
16248     0f 85/jump-if-!= $array-element-type-id:error2/disp32
16249     # if t->left != array abort
16250     {
16251       50/push-eax
16252       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
16253       (is-simple-mu-type? %eax 3)  # array => eax
16254       3d/compare-eax-with 0/imm32/false
16255       58/pop-to-eax
16256 $array-element-type-id:no-array:
16257       0f 84/jump-if-= $array-element-type-id:error2/disp32
16258     }
16259 $array-element-type-id:skip-array:
16260     # t = t->right
16261     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
16262     # if t == 0 abort
16263     3d/compare-eax-with 0/imm32
16264     0f 84/jump-if-= $array-element-type-id:error2/disp32
16265     # if t->is-atom? abort
16266     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
16267     0f 85/jump-if-!= $array-element-type-id:error2/disp32
16268     # return t->left->value
16269     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
16270     8b/-> *(eax+4) 0/r32/eax  # Type-tree-value
16271 $array-element-type-id:end:
16272     # . epilogue
16273     89/<- %esp 5/r32/ebp
16274     5d/pop-to-ebp
16275     c3/return
16276 
16277 $array-element-type-id:error0:
16278     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
16279     50/push-eax
16280     8b/-> *(ebp+8) 0/r32/eax
16281     (lookup *eax *(eax+4))  # Var-name Var-name => eax
16282     (write-buffered *(ebp+0xc) %eax)
16283     58/pop-to-eax
16284     (write-buffered *(ebp+0xc) "' has no type\n")
16285     (flush *(ebp+0xc))
16286     (stop *(ebp+0x10) 1)
16287     # never gets here
16288 
16289 $array-element-type-id:error1:
16290     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
16291     50/push-eax
16292     8b/-> *(ebp+8) 0/r32/eax
16293     (lookup *eax *(eax+4))  # Var-name Var-name => eax
16294     (write-buffered *(ebp+0xc) %eax)
16295     58/pop-to-eax
16296     (write-buffered *(ebp+0xc) "' has atomic type ")
16297     (write-int32-hex-buffered *(ebp+0xc) *(eax+4))  # Type-tree-value
16298     (write-buffered *(ebp+0xc) Newline)
16299     (flush *(ebp+0xc))
16300     (stop *(ebp+0x10) 1)
16301     # never gets here
16302 
16303 $array-element-type-id:error2:
16304     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
16305     50/push-eax
16306     8b/-> *(ebp+8) 0/r32/eax
16307     (lookup *eax *(eax+4))  # Var-name Var-name => eax
16308     (write-buffered *(ebp+0xc) %eax)
16309     58/pop-to-eax
16310     (write-buffered *(ebp+0xc) "' has non-array type\n")
16311     (flush *(ebp+0xc))
16312     (stop *(ebp+0x10) 1)
16313     # never gets here
16314 
16315 size-of-type-id-as-array-element:  # t: type-id -> result/eax: int
16316     # . prologue
16317     55/push-ebp
16318     89/<- %ebp 4/r32/esp
16319     # eax = t
16320     8b/-> *(ebp+8) 0/r32/eax
16321     # if t is 'byte', size is 1
16322     3d/compare-eax-and 8/imm32/byte
16323     {
16324       75/jump-if-!= break/disp8
16325       b8/copy-to-eax 1/imm32
16326       eb/jump $size-of-type-id-as-array-element:end/disp8
16327     }
16328     # otherwise proceed as usual
16329     (size-of-type-id %eax)  # => eax
16330 $size-of-type-id-as-array-element:end:
16331     # . epilogue
16332     89/<- %esp 5/r32/ebp
16333     5d/pop-to-ebp
16334     c3/return
16335 
16336 emit-save-size-to:  # out: (addr buffered-file), base: (addr var), outreg: (addr array byte)
16337     # . prologue
16338     55/push-ebp
16339     89/<- %ebp 4/r32/esp
16340     # . save registers
16341     50/push-eax
16342     53/push-ebx
16343     # ebx = base
16344     8b/-> *(ebp+0xc) 3/r32/ebx
16345     (emit-indent *(ebp+8) *Curr-block-depth)
16346     (write-buffered *(ebp+8) "8b/-> *")
16347     # if base is an (addr array ...) in a register
16348     {
16349       81 7/subop/compare *(ebx+0x18)) 0/imm32  # Var-register
16350       74/jump-if-= break/disp8
16351 $emit-save-size-to:emit-base-from-register:
16352       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
16353       (write-buffered *(ebp+8) %eax)
16354       eb/jump $emit-save-size-to:emit-output/disp8
16355     }
16356     # otherwise if base is an (array ...) on the stack
16357     {
16358       81 7/subop/compare *(ebx+0x14)) 0/imm32  # Var-offset
16359       74/jump-if-= break/disp8
16360 $emit-save-size-to:emit-base-from-stack:
16361       (write-buffered *(ebp+8) "(ebp+")
16362       (write-int32-hex-buffered *(ebp+8) *(ebx+0x14))  # Var-offset
16363       (write-buffered *(ebp+8) ")")
16364     }
16365 $emit-save-size-to:emit-output:
16366     (write-buffered *(ebp+8) " ")
16367     (get Mu-registers *(ebp+0x10) 0xc "Mu-registers")  # => eax
16368     (write-int32-hex-buffered *(ebp+8) *eax)
16369     (write-buffered *(ebp+8) "/r32\n")
16370 $emit-save-size-to:end:
16371     # . restore registers
16372     5b/pop-to-ebx
16373     58/pop-to-eax
16374     # . epilogue
16375     89/<- %esp 5/r32/ebp
16376     5d/pop-to-ebp
16377     c3/return
16378 
16379 emit-divide-by-shift-right:  # out: (addr buffered-file), reg: (addr array byte), size: int
16380     # . prologue
16381     55/push-ebp
16382     89/<- %ebp 4/r32/esp
16383     # . save registers
16384     50/push-eax
16385     #
16386     (emit-indent *(ebp+8) *Curr-block-depth)
16387     (write-buffered *(ebp+8) "c1/shift 5/subop/>> %")
16388     (write-buffered *(ebp+8) *(ebp+0xc))
16389     (write-buffered *(ebp+8) Space)
16390     (num-shift-rights *(ebp+0x10))  # => eax
16391     (write-int32-hex-buffered *(ebp+8) %eax)
16392     (write-buffered *(ebp+8) "/imm8\n")
16393 $emit-divide-by-shift-right:end:
16394     # . restore registers
16395     58/pop-to-eax
16396     # . epilogue
16397     89/<- %esp 5/r32/ebp
16398     5d/pop-to-ebp
16399     c3/return
16400 
16401 translate-mu-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
16402     # . prologue
16403     55/push-ebp
16404     89/<- %ebp 4/r32/esp
16405     # . save registers
16406     51/push-ecx
16407     # ecx = stmt
16408     8b/-> *(ebp+0xc) 1/r32/ecx
16409     # var base/ecx: (addr var) = stmt->inouts[0]
16410     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16411     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16412     89/<- %ecx 0/r32/eax
16413     # if (var->register) do one thing
16414     {
16415       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
16416       74/jump-if-= break/disp8
16417       # TODO: ensure there's no dereference
16418       (translate-mu-index-stmt-with-array-in-register *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
16419       eb/jump $translate-mu-index-stmt:end/disp8
16420     }
16421     # if (var->offset) do a different thing
16422     {
16423       81 7/subop/compare *(ecx+0x14) 0/imm32  # Var-offset
16424       74/jump-if-= break/disp8
16425       # TODO: ensure there's no dereference
16426       (translate-mu-index-stmt-with-array-on-stack *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
16427       eb/jump $translate-mu-index-stmt:end/disp8
16428     }
16429 $translate-mu-index-stmt:end:
16430     # . restore registers
16431     59/pop-to-ecx
16432     # . epilogue
16433     89/<- %esp 5/r32/ebp
16434     5d/pop-to-ebp
16435     c3/return
16436 
16437 $translate-mu-index-stmt-with-array:error1:
16438     (write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input must either lie in a register or be a literal\n")
16439     (flush *(ebp+0x10))
16440     (stop *(ebp+0x14) 1)
16441     # never gets here
16442 
16443 $translate-mu-index-stmt-with-array:error2:
16444     (write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input when in a register must be an int or offset\n")
16445     (flush *(ebp+0x10))
16446     (stop *(ebp+0x14) 1)
16447     # never gets here
16448 
16449 translate-mu-index-stmt-with-array-in-register:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
16450     # . prologue
16451     55/push-ebp
16452     89/<- %ebp 4/r32/esp
16453     # . save registers
16454     50/push-eax
16455     51/push-ecx
16456     52/push-edx
16457     53/push-ebx
16458     #
16459     (emit-indent *(ebp+8) *Curr-block-depth)
16460     (write-buffered *(ebp+8) "8d/copy-address *(")
16461     # TODO: ensure inouts[0] is in a register and not dereferenced
16462 $translate-mu-index-stmt-with-array-in-register:emit-base:
16463     # ecx = stmt
16464     8b/-> *(ebp+0xc) 1/r32/ecx
16465     # var base/ebx: (addr var) = inouts[0]
16466     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16467     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16468     89/<- %ebx 0/r32/eax
16469     # print base->register " + "
16470     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
16471     (write-buffered *(ebp+8) %eax)
16472     (write-buffered *(ebp+8) " + ")
16473     # var index/edx: (addr var) = inouts[1]
16474     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16475     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
16476     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16477     89/<- %edx 0/r32/eax
16478     # if index->register
16479     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
16480     {
16481       0f 84/jump-if-= break/disp32
16482 $translate-mu-index-stmt-with-array-in-register:emit-register-index:
16483       # if index is an int
16484       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
16485       (is-simple-mu-type? %eax 1)  # int => eax
16486       3d/compare-eax-and 0/imm32/false
16487       {
16488         0f 84/jump-if-= break/disp32
16489 $translate-mu-index-stmt-with-array-in-register:emit-int-register-index:
16490         # print index->register "<<" log2(array-element-size(base)) " + 4) "
16491         # . index->register "<<"
16492         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
16493         (write-buffered *(ebp+8) %eax)
16494         (write-buffered *(ebp+8) "<<")
16495         # . log2(array-element-size(base->type))
16496         # TODO: ensure size is a power of 2
16497         (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
16498         (num-shift-rights %eax)  # => eax
16499         (write-int32-hex-buffered *(ebp+8) %eax)
16500         e9/jump $translate-mu-index-stmt-with-array-in-register:emit-register-index-done/disp32
16501       }
16502       # if index->type is any other atom, abort
16503       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
16504       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
16505       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
16506       # if index has type (offset ...)
16507       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
16508       (is-simple-mu-type? %eax 7)  # => eax
16509       3d/compare-eax-and 0/imm32/false
16510       {
16511         0f 84/jump-if-= break/disp32
16512         # print index->register
16513 $translate-mu-index-stmt-with-array-in-register:emit-offset-register-index:
16514         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
16515         (write-buffered *(ebp+8) %eax)
16516       }
16517 $translate-mu-index-stmt-with-array-in-register:emit-register-index-done:
16518       (write-buffered *(ebp+8) " + 4) ")
16519       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
16520     }
16521     # otherwise if index is a literal
16522     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
16523     (is-simple-mu-type? %eax 0)  # => eax
16524     3d/compare-eax-and 0/imm32/false
16525     {
16526       0f 84/jump-if-= break/disp32
16527 $translate-mu-index-stmt-with-array-in-register:emit-literal-index:
16528       # var index-value/edx: int = parse-hex-int(index->name)
16529       (lookup *edx *(edx+4))  # Var-name Var-name => eax
16530       (parse-hex-int %eax)  # => eax
16531       89/<- %edx 0/r32/eax
16532       # offset = idx-value * array-element-size(base->type)
16533       (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
16534       f7 4/subop/multiply-into-eax %edx  # clobbers edx
16535       # offset += 4 for array size
16536       05/add-to-eax 4/imm32
16537       # TODO: check edx for overflow
16538       # print offset
16539       (write-int32-hex-buffered *(ebp+8) %eax)
16540       (write-buffered *(ebp+8) ") ")
16541       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
16542     }
16543     # otherwise abort
16544     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
16545 $translate-mu-index-stmt-with-array-in-register:emit-output:
16546     # outputs[0] "/r32"
16547     8b/-> *(ebp+0xc) 1/r32/ecx
16548     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
16549     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16550     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
16551     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
16552     (write-int32-hex-buffered *(ebp+8) *eax)
16553     (write-buffered *(ebp+8) "/r32\n")
16554 $translate-mu-index-stmt-with-array-in-register:end:
16555     # . restore registers
16556     5b/pop-to-ebx
16557     5a/pop-to-edx
16558     59/pop-to-ecx
16559     58/pop-to-eax
16560     # . epilogue
16561     89/<- %esp 5/r32/ebp
16562     5d/pop-to-ebp
16563     c3/return
16564 
16565 translate-mu-index-stmt-with-array-on-stack:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
16566     # . prologue
16567     55/push-ebp
16568     89/<- %ebp 4/r32/esp
16569     # . save registers
16570     50/push-eax
16571     51/push-ecx
16572     52/push-edx
16573     53/push-ebx
16574     #
16575     (emit-indent *(ebp+8) *Curr-block-depth)
16576     (write-buffered *(ebp+8) "8d/copy-address *(ebp + ")
16577     # var curr/edx: (addr stmt-var) = lookup(stmt->inouts)
16578     8b/-> *(ebp+0xc) 0/r32/eax
16579     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16580     89/<- %edx 0/r32/eax
16581     # var base/ecx: (addr var) = lookup(curr->value)
16582     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16583     89/<- %ecx 0/r32/eax
16584     # var curr2/eax: (addr stmt-var) = lookup(curr->next)
16585     (lookup *(edx+8) *(edx+0xc))  # Stmt-var-next Stmt-var-next => eax
16586     # var index/edx: (handle var) = curr2->value
16587     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16588     89/<- %edx 0/r32/eax
16589     # if index->register
16590     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
16591     {
16592       0f 84/jump-if-= break/disp32
16593 $translate-mu-index-stmt-with-array-on-stack:emit-register-index:
16594       # if index is an int
16595       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
16596       (is-simple-mu-type? %eax 1)  # int => eax
16597       3d/compare-eax-and 0/imm32/false
16598       {
16599         0f 84/jump-if-= break/disp32
16600 $translate-mu-index-stmt-with-array-on-stack:emit-int-register-index:
16601         # print index->register "<<" log2(array-element-size(base)) " + " base->offset+4
16602         # . inouts[1]->register "<<"
16603         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
16604         (write-buffered *(ebp+8) %eax)
16605         (write-buffered *(ebp+8) "<<")
16606         # . log2(array-element-size(base))
16607         # TODO: ensure size is a power of 2
16608         (array-element-size %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
16609         (num-shift-rights %eax)  # => eax
16610         (write-int32-hex-buffered *(ebp+8) %eax)
16611         #
16612         (write-buffered *(ebp+8) " + ")
16613         #
16614         8b/-> *(ecx+0x14) 0/r32/eax  # Var-offset
16615         05/add-to-eax 4/imm32  # for array length
16616         (write-int32-hex-buffered *(ebp+8) %eax)
16617         e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done/disp32
16618       }
16619       # if index->type is any other atom, abort
16620       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
16621       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
16622       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
16623       # if index has type (offset ...)
16624       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
16625       (is-simple-mu-type? %eax 7)  # => eax
16626       3d/compare-eax-and 0/imm32/false
16627       {
16628         0f 84/jump-if-= break/disp32
16629         # print index->register
16630 $translate-mu-index-stmt-with-array-on-stack:emit-offset-register-index:
16631         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
16632         (write-buffered *(ebp+8) %eax)
16633       }
16634 $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done:
16635       (write-buffered *(ebp+8) ") ")
16636       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
16637     }
16638     # otherwise if index is a literal
16639     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
16640     (is-simple-mu-type? %eax 0)  # => eax
16641     3d/compare-eax-and 0/imm32/false
16642     {
16643       0f 84/jump-if-= break/disp32
16644 $translate-mu-index-stmt-with-array-on-stack:emit-literal-index:
16645       # var idx-value/edx: int = parse-hex-int(index->name)
16646       (lookup *edx *(edx+4))  # Var-name Var-name => eax
16647       (parse-hex-int %eax)  # Var-name => eax
16648       89/<- %edx 0/r32/eax
16649       # offset = idx-value * array-element-size(base)
16650       (array-element-size %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
16651       f7 4/subop/multiply-into-eax %edx  # clobbers edx
16652       # offset += base->offset
16653       03/add *(ecx+0x14) 0/r32/eax  # Var-offset
16654       # offset += 4 for array size
16655       05/add-to-eax 4/imm32
16656       # TODO: check edx for overflow
16657       # print offset
16658       (write-int32-hex-buffered *(ebp+8) %eax)
16659       (write-buffered *(ebp+8) ") ")
16660       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
16661     }
16662     # otherwise abort
16663     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
16664 $translate-mu-index-stmt-with-array-on-stack:emit-output:
16665     # outputs[0] "/r32"
16666     8b/-> *(ebp+0xc) 0/r32/eax
16667     (lookup *(eax+0x14) *(eax+0x18))  # Stmt1-outputs Stmt1-outputs => eax
16668     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16669     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
16670     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
16671     (write-int32-hex-buffered *(ebp+8) *eax)
16672     (write-buffered *(ebp+8) "/r32\n")
16673 $translate-mu-index-stmt-with-array-on-stack:end:
16674     # . restore registers
16675     5b/pop-to-ebx
16676     5a/pop-to-edx
16677     59/pop-to-ecx
16678     58/pop-to-eax
16679     # . epilogue
16680     89/<- %esp 5/r32/ebp
16681     5d/pop-to-ebp
16682     c3/return
16683 
16684 translate-mu-compute-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
16685     # . prologue
16686     55/push-ebp
16687     89/<- %ebp 4/r32/esp
16688     # . save registers
16689     50/push-eax
16690     51/push-ecx
16691     52/push-edx
16692     53/push-ebx
16693     #
16694     (emit-indent *(ebp+8) *Curr-block-depth)
16695     (write-buffered *(ebp+8) "69/multiply")
16696     # ecx = stmt
16697     8b/-> *(ebp+0xc) 1/r32/ecx
16698     # var first-inout/ebx: (addr stmt-var) = stmt->inouts[0]
16699     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16700     89/<- %ebx 0/r32/eax
16701 $translate-mu-compute-index-stmt:emit-index:
16702     (lookup *(ebx+8) *(ebx+0xc))  # Stmt-var-next Stmt-var-next => eax
16703     (emit-subx-var-as-rm32 *(ebp+8) %eax)
16704     (write-buffered *(ebp+8) Space)
16705 $translate-mu-compute-index-stmt:emit-elem-size:
16706     # var base/ebx: (addr var)
16707     (lookup *ebx *(ebx+4))  # Stmt-var-value Stmt-var-value => eax
16708     89/<- %ebx 0/r32/eax
16709     # print array-element-size(base)
16710     (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
16711     (write-int32-hex-buffered *(ebp+8) %eax)
16712     (write-buffered *(ebp+8) "/imm32 ")
16713 $translate-mu-compute-index-stmt:emit-output:
16714     # outputs[0] "/r32"
16715     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
16716     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16717     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
16718     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
16719     (write-int32-hex-buffered *(ebp+8) *eax)
16720     (write-buffered *(ebp+8) "/r32\n")
16721 $translate-mu-compute-index-stmt:end:
16722     # . restore registers
16723     5b/pop-to-ebx
16724     5a/pop-to-edx
16725     59/pop-to-ecx
16726     58/pop-to-eax
16727     # . epilogue
16728     89/<- %esp 5/r32/ebp
16729     5d/pop-to-ebp
16730     c3/return
16731 
16732 translate-mu-get-stmt:  # out: (addr buffered-file), stmt: (addr stmt)
16733     # . prologue
16734     55/push-ebp
16735     89/<- %ebp 4/r32/esp
16736     # . save registers
16737     50/push-eax
16738     51/push-ecx
16739     52/push-edx
16740     #
16741     (emit-indent *(ebp+8) *Curr-block-depth)
16742     (write-buffered *(ebp+8) "8d/copy-address ")
16743     # ecx = stmt
16744     8b/-> *(ebp+0xc) 1/r32/ecx
16745     # var offset/edx: int = get offset of stmt
16746     (mu-get-offset %ecx)  # => eax
16747     89/<- %edx 0/r32/eax
16748     # var base/eax: (addr var) = stmt->inouts->value
16749     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16750     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16751     # if base is in a register
16752     81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
16753     {
16754       0f 84/jump-if-= break/disp32
16755 $translate-mu-get-stmt:emit-register-input:
16756       # emit "*(" base->register " + " offset ") "
16757       (write-buffered *(ebp+8) "*(")
16758       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
16759       (write-buffered *(ebp+8) %eax)
16760       (write-buffered *(ebp+8) " + ")
16761       (write-int32-hex-buffered *(ebp+8) %edx)
16762       (write-buffered *(ebp+8) ") ")
16763       e9/jump $translate-mu-get-stmt:emit-output/disp32
16764     }
16765     # otherwise base is on the stack
16766     {
16767 $translate-mu-get-stmt:emit-stack-input:
16768       # emit "*(ebp + " inouts[0]->stack-offset + offset ") "
16769       (write-buffered *(ebp+8) "*(ebp+")
16770       03/add *(eax+0x14) 2/r32/edx  # Var-offset
16771       (write-int32-hex-buffered *(ebp+8) %edx)
16772       (write-buffered *(ebp+8) ") ")
16773       eb/jump $translate-mu-get-stmt:emit-output/disp8
16774     }
16775 $translate-mu-get-stmt:emit-output:
16776     # var output/eax: (addr var) = stmt->outputs->value
16777     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
16778     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16779     # emit offset->register "/r32"
16780     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
16781     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
16782     (write-int32-hex-buffered *(ebp+8) *eax)
16783     (write-buffered *(ebp+8) "/r32\n")
16784 $translate-mu-get-stmt:end:
16785     # . restore registers
16786     5a/pop-to-edx
16787     59/pop-to-ecx
16788     58/pop-to-eax
16789     # . epilogue
16790     89/<- %esp 5/r32/ebp
16791     5d/pop-to-ebp
16792     c3/return
16793 
16794 translate-mu-allocate-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
16795     # . prologue
16796     55/push-ebp
16797     89/<- %ebp 4/r32/esp
16798     # . save registers
16799     50/push-eax
16800     56/push-esi
16801     57/push-edi
16802     # esi = stmt
16803     8b/-> *(ebp+0xc) 6/r32/esi
16804     # var target/edi: (addr stmt-var) = stmt->inouts[0]
16805     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16806     89/<- %edi 0/r32/eax
16807     #
16808     (emit-indent *(ebp+8) *Curr-block-depth)
16809     (write-buffered *(ebp+8) "(allocate Heap ")
16810     (addr-handle-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
16811     (write-int32-hex-buffered *(ebp+8) %eax)
16812     (emit-subx-call-operand *(ebp+8) %edi)
16813     (write-buffered *(ebp+8) ")\n")
16814 $translate-mu-allocate-stmt:end:
16815     # . restore registers
16816     5f/pop-to-edi
16817     5e/pop-to-esi
16818     58/pop-to-eax
16819     # . epilogue
16820     89/<- %esp 5/r32/ebp
16821     5d/pop-to-ebp
16822     c3/return
16823 
16824 addr-handle-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
16825     # . prologue
16826     55/push-ebp
16827     89/<- %ebp 4/r32/esp
16828     # var t/eax: (addr type-tree) = s->value->type
16829     8b/-> *(ebp+8) 0/r32/eax
16830     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16831     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
16832     # TODO: check eax != 0
16833     # TODO: check !t->is-atom?
16834     # TODO: check t->left == addr
16835     # t = t->right
16836 $addr-handle-payload-size:skip-addr:
16837     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
16838     # TODO: check eax != 0
16839     # TODO: check !t->is-atom?
16840     # TODO: check t->left == handle
16841     # t = t->right
16842 $addr-handle-payload-size:skip-handle:
16843     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
16844     # TODO: check eax != 0
16845     # if !t->is-atom? t = t->left
16846     81 7/subop/compare *eax 0/imm32/false
16847     {
16848       75/jump-if-!= break/disp8
16849       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
16850     }
16851     # TODO: check t->is-atom?
16852     # return size(t->value)
16853     (size-of-type-id *(eax+4))  # Type-tree-value => eax
16854 $addr-handle-payload-size:end:
16855     # . epilogue
16856     89/<- %esp 5/r32/ebp
16857     5d/pop-to-ebp
16858     c3/return
16859 
16860 addr-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
16861     # . prologue
16862     55/push-ebp
16863     89/<- %ebp 4/r32/esp
16864     # var t/eax: (addr type-tree) = s->value->type
16865     8b/-> *(ebp+8) 0/r32/eax
16866     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16867     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
16868     # TODO: check eax != 0
16869     # TODO: check !t->is-atom?
16870     # TODO: check t->left == addr
16871     # t = t->right
16872 $addr-payload-size:skip-addr:
16873     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
16874     # TODO: check eax != 0
16875     # if !t->is-atom? t = t->left
16876     81 7/subop/compare *eax 0/imm32/false
16877     {
16878       75/jump-if-!= break/disp8
16879       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
16880     }
16881     # TODO: check t->is-atom?
16882     # return size(t->value)
16883     (size-of-type-id *(eax+4))  # Type-tree-value => eax
16884 $addr-payload-size:end:
16885     # . epilogue
16886     89/<- %esp 5/r32/ebp
16887     5d/pop-to-ebp
16888     c3/return
16889 
16890 translate-mu-populate-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
16891     # . prologue
16892     55/push-ebp
16893     89/<- %ebp 4/r32/esp
16894     # . save registers
16895     50/push-eax
16896     51/push-ecx
16897     56/push-esi
16898     57/push-edi
16899     # esi = stmt
16900     8b/-> *(ebp+0xc) 6/r32/esi
16901     # var target/edi: (addr stmt-var) = stmt->inouts[0]
16902     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16903     89/<- %edi 0/r32/eax
16904     # var len/ecx: (addr stmt-var) = stmt->inouts[1]
16905     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
16906     89/<- %ecx 0/r32/eax
16907     #
16908     (emit-indent *(ebp+8) *Curr-block-depth)
16909     (write-buffered *(ebp+8) "(allocate-array2 Heap ")
16910     (addr-handle-array-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
16911     (write-int32-hex-buffered *(ebp+8) %eax)
16912     (emit-subx-call-operand *(ebp+8) %ecx)
16913     (emit-subx-call-operand *(ebp+8) %edi)
16914     (write-buffered *(ebp+8) ")\n")
16915 $translate-mu-populate-stmt:end:
16916     # . restore registers
16917     5f/pop-to-edi
16918     5e/pop-to-esi
16919     59/pop-to-ecx
16920     58/pop-to-eax
16921     # . epilogue
16922     89/<- %esp 5/r32/ebp
16923     5d/pop-to-ebp
16924     c3/return
16925 
16926 translate-mu-populate-stream-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
16927     # . prologue
16928     55/push-ebp
16929     89/<- %ebp 4/r32/esp
16930     # . save registers
16931     50/push-eax
16932     51/push-ecx
16933     56/push-esi
16934     57/push-edi
16935     # esi = stmt
16936     8b/-> *(ebp+0xc) 6/r32/esi
16937     # var target/edi: (addr stmt-var) = stmt->inouts[0]
16938     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16939     89/<- %edi 0/r32/eax
16940     # var len/ecx: (addr stmt-var) = stmt->inouts[1]
16941     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
16942     89/<- %ecx 0/r32/eax
16943     #
16944     (emit-indent *(ebp+8) *Curr-block-depth)
16945     (write-buffered *(ebp+8) "(new-stream Heap ")
16946     (addr-handle-stream-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
16947     (write-int32-hex-buffered *(ebp+8) %eax)
16948     (emit-subx-call-operand *(ebp+8) %ecx)
16949     (emit-subx-call-operand *(ebp+8) %edi)
16950     (write-buffered *(ebp+8) ")\n")
16951 $translate-mu-populate-stream-stmt:end:
16952     # . restore registers
16953     5f/pop-to-edi
16954     5e/pop-to-esi
16955     59/pop-to-ecx
16956     58/pop-to-eax
16957     # . epilogue
16958     89/<- %esp 5/r32/ebp
16959     5d/pop-to-ebp
16960     c3/return
16961 
16962 translate-mu-read-from-stream-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
16963     # . prologue
16964     55/push-ebp
16965     89/<- %ebp 4/r32/esp
16966     # . save registers
16967     50/push-eax
16968     51/push-ecx
16969     56/push-esi
16970     57/push-edi
16971     # esi = stmt
16972     8b/-> *(ebp+0xc) 6/r32/esi
16973     # var stream/ecx: (addr stmt-var) = stmt->inouts[0]
16974     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16975     89/<- %ecx 0/r32/eax
16976     # var target/edi: (addr stmt-var) = stmt->inouts[1]
16977     (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
16978     89/<- %edi 0/r32/eax
16979     #
16980     (emit-indent *(ebp+8) *Curr-block-depth)
16981     (write-buffered *(ebp+8) "(read-from-stream")
16982     (emit-subx-call-operand *(ebp+8) %ecx)
16983     (emit-subx-call-operand *(ebp+8) %edi)
16984     (write-buffered *(ebp+8) Space)
16985     (addr-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
16986     (write-int32-hex-buffered *(ebp+8) %eax)
16987     (write-buffered *(ebp+8) ")\n")
16988 $translate-mu-read-from-stream-stmt:end:
16989     # . restore registers
16990     5f/pop-to-edi
16991     5e/pop-to-esi
16992     59/pop-to-ecx
16993     58/pop-to-eax
16994     # . epilogue
16995     89/<- %esp 5/r32/ebp
16996     5d/pop-to-ebp
16997     c3/return
16998 
16999 translate-mu-write-to-stream-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
17000     # . prologue
17001     55/push-ebp
17002     89/<- %ebp 4/r32/esp
17003     # . save registers
17004     50/push-eax
17005     51/push-ecx
17006     56/push-esi
17007     57/push-edi
17008     # esi = stmt
17009     8b/-> *(ebp+0xc) 6/r32/esi
17010     # var stream/ecx: (addr stmt-var) = stmt->inouts[0]
17011     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17012     89/<- %ecx 0/r32/eax
17013     # var target/edi: (addr stmt-var) = stmt->inouts[1]
17014     (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
17015     89/<- %edi 0/r32/eax
17016     #
17017     (emit-indent *(ebp+8) *Curr-block-depth)
17018     (write-buffered *(ebp+8) "(write-to-stream")
17019     (emit-subx-call-operand *(ebp+8) %ecx)
17020     (flush *(ebp+8))
17021     (emit-subx-call-operand *(ebp+8) %edi)
17022     (flush *(ebp+8))
17023     (write-buffered *(ebp+8) Space)
17024     (flush *(ebp+8))
17025     (addr-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
17026     (write-int32-hex-buffered *(ebp+8) %eax)
17027     (write-buffered *(ebp+8) ")\n")
17028 $translate-mu-write-to-stream-stmt:end:
17029     # . restore registers
17030     5f/pop-to-edi
17031     5e/pop-to-esi
17032     59/pop-to-ecx
17033     58/pop-to-eax
17034     # . epilogue
17035     89/<- %esp 5/r32/ebp
17036     5d/pop-to-ebp
17037     c3/return
17038 
17039 addr-handle-array-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
17040     # . prologue
17041     55/push-ebp
17042     89/<- %ebp 4/r32/esp
17043     # var t/eax: (addr type-tree) = s->value->type
17044     8b/-> *(ebp+8) 0/r32/eax
17045     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17046     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
17047     # TODO: check eax != 0
17048     # TODO: check !t->is-atom?
17049     # TODO: check t->left == addr
17050     # t = t->right
17051 $addr-handle-array-payload-size:skip-addr:
17052     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17053     # TODO: check eax != 0
17054     # TODO: check !t->is-atom?
17055     # TODO: check t->left == handle
17056     # t = t->right
17057 $addr-handle-array-payload-size:skip-handle:
17058     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17059     # TODO: check eax != 0
17060     # TODO: check !t->is-atom?
17061     # TODO: check t->left == array
17062     # t = t->right
17063 $addr-handle-array-payload-size:skip-array:
17064     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17065     # TODO: check eax != 0
17066     # if !t->is-atom? t = t->left
17067     81 7/subop/compare *eax 0/imm32/false
17068     {
17069       75/jump-if-!= break/disp8
17070       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
17071     }
17072 $addr-handle-array-payload-size:compute-size:
17073     # TODO: check t->is-atom?
17074     # return size(t->value)
17075     (size-of-type-id-as-array-element *(eax+4))  # Type-tree-value => eax
17076 $addr-handle-array-payload-size:end:
17077     # . epilogue
17078     89/<- %esp 5/r32/ebp
17079     5d/pop-to-ebp
17080     c3/return
17081 
17082 addr-handle-stream-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
17083     # . prologue
17084     55/push-ebp
17085     89/<- %ebp 4/r32/esp
17086     # var t/eax: (addr type-tree) = s->value->type
17087     8b/-> *(ebp+8) 0/r32/eax
17088     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17089     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
17090     # TODO: check eax != 0
17091     # TODO: check !t->is-atom?
17092     # TODO: check t->left == addr
17093     # t = t->right
17094 $addr-handle-stream-payload-size:skip-addr:
17095     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17096     # TODO: check eax != 0
17097     # TODO: check !t->is-atom?
17098     # TODO: check t->left == handle
17099     # t = t->right
17100 $addr-handle-stream-payload-size:skip-handle:
17101     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17102     # TODO: check eax != 0
17103     # TODO: check !t->is-atom?
17104     # TODO: check t->left == stream
17105     # t = t->right
17106 $addr-handle-stream-payload-size:skip-stream:
17107     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17108     # TODO: check eax != 0
17109     # if !t->is-atom? t = t->left
17110     81 7/subop/compare *eax 0/imm32/false
17111     {
17112       75/jump-if-!= break/disp8
17113       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
17114     }
17115 $addr-handle-stream-payload-size:compute-size:
17116     # TODO: check t->is-atom?
17117     # return size(t->value)
17118     (size-of-type-id-as-array-element *(eax+4))  # Type-tree-value => eax
17119 $addr-handle-stream-payload-size:end:
17120     # . epilogue
17121     89/<- %esp 5/r32/ebp
17122     5d/pop-to-ebp
17123     c3/return
17124 
17125 power-of-2?:  # n: int, err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: boolean
17126     # precondition: n is positive
17127     # . prologue
17128     55/push-ebp
17129     89/<- %ebp 4/r32/esp
17130     # eax = n
17131     8b/-> *(ebp+8) 0/r32/eax
17132     # if (n < 0) abort
17133     3d/compare-eax-with 0/imm32
17134     0f 8c/jump-if-< $power-of-2?:abort/disp32
17135     # var tmp/eax: int = n-1
17136     48/decrement-eax
17137     # var tmp2/eax: int = n & tmp
17138     23/and-> *(ebp+8) 0/r32/eax
17139     # return (tmp2 == 0)
17140     3d/compare-eax-and 0/imm32
17141     0f 94/set-byte-if-= %al
17142     81 4/subop/and %eax 0xff/imm32
17143 $power-of-2?:end:
17144     # . epilogue
17145     89/<- %esp 5/r32/ebp
17146     5d/pop-to-ebp
17147     c3/return
17148 
17149 $power-of-2?:abort:
17150     (write-buffered *(ebp+0xc) "power-of-2?: negative number\n")
17151     (flush *(ebp+0xc))
17152     (stop *(ebp+0x10) 1)
17153     # never gets here
17154 
17155 num-shift-rights:  # n: int -> result/eax: int
17156     # precondition: n is a positive power of 2
17157     # . prologue
17158     55/push-ebp
17159     89/<- %ebp 4/r32/esp
17160     # . save registers
17161     51/push-ecx
17162     # var curr/ecx: int = n
17163     8b/-> *(ebp+8) 1/r32/ecx
17164     # result = 0
17165     b8/copy-to-eax 0/imm32
17166     {
17167       # if (curr <= 1) break
17168       81 7/subop/compare %ecx 1/imm32
17169       7e/jump-if-<= break/disp8
17170       40/increment-eax
17171       c1/shift 5/subop/arithmetic-right %ecx 1/imm8
17172       eb/jump loop/disp8
17173     }
17174 $num-shift-rights:end:
17175     # . restore registers
17176     59/pop-to-ecx
17177     # . epilogue
17178     89/<- %esp 5/r32/ebp
17179     5d/pop-to-ebp
17180     c3/return
17181 
17182 mu-get-offset:  # stmt: (addr stmt) -> result/eax: int
17183     # . prologue
17184     55/push-ebp
17185     89/<- %ebp 4/r32/esp
17186     # var second-inout/eax: (addr stmt-var) = stmt->inouts->next
17187     8b/-> *(ebp+8) 0/r32/eax
17188     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17189     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
17190     # var output-var/eax: (addr var) = second-inout->value
17191     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17192 #?     (write-buffered Stderr "mu-get-offset: ")
17193 #?     (write-int32-hex-buffered Stderr %eax)
17194 #?     (write-buffered Stderr " name: ")
17195 #?     50/push-eax
17196 #?     (lookup *eax *(eax+4))  # Var-name
17197 #?     (write-buffered Stderr %eax)
17198 #?     58/pop-to-eax
17199 #?     (write-buffered Stderr Newline)
17200 #?     (flush Stderr)
17201     # return output-var->stack-offset
17202     8b/-> *(eax+0x14) 0/r32/eax  # Var-offset
17203 #?     (write-buffered Stderr "=> ")
17204 #?     (write-int32-hex-buffered Stderr %eax)
17205 #?     (write-buffered Stderr Newline)
17206 #?     (flush Stderr)
17207 $emit-get-offset:end:
17208     # . epilogue
17209     89/<- %esp 5/r32/ebp
17210     5d/pop-to-ebp
17211     c3/return
17212 
17213 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)
17214     # . prologue
17215     55/push-ebp
17216     89/<- %ebp 4/r32/esp
17217     # . save registers
17218     50/push-eax
17219     51/push-ecx
17220     56/push-esi
17221     # esi = block
17222     8b/-> *(ebp+0xc) 6/r32/esi
17223     # block->var->block-depth = *Curr-block-depth
17224     (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
17225     8b/-> *Curr-block-depth 1/r32/ecx
17226     89/<- *(eax+0x10) 1/r32/ecx  # Var-block-depth
17227     # var stmts/eax: (addr list stmt) = lookup(block->statements)
17228     (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
17229     #
17230     {
17231 $emit-subx-block:check-empty:
17232       3d/compare-eax-and 0/imm32
17233       0f 84/jump-if-= break/disp32
17234       (emit-indent *(ebp+8) *Curr-block-depth)
17235       (write-buffered *(ebp+8) "{\n")
17236       # var v/ecx: (addr var) = lookup(block->var)
17237       (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
17238       89/<- %ecx 0/r32/eax
17239       #
17240       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
17241       (write-buffered *(ebp+8) %eax)
17242       (write-buffered *(ebp+8) ":loop:\n")
17243       ff 0/subop/increment *Curr-block-depth
17244       (push *(ebp+0x10) *(esi+0xc))  # Block-var
17245       (push *(ebp+0x10) *(esi+0x10))  # Block-var
17246       (push *(ebp+0x10) 0)  # false
17247       # emit block->statements
17248       (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
17249       (emit-subx-stmt-list *(ebp+8) %eax *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
17250       (pop *(ebp+0x10))  # => eax
17251       (pop *(ebp+0x10))  # => eax
17252       (pop *(ebp+0x10))  # => eax
17253       ff 1/subop/decrement *Curr-block-depth
17254       (emit-indent *(ebp+8) *Curr-block-depth)
17255       (write-buffered *(ebp+8) "}\n")
17256       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
17257       (write-buffered *(ebp+8) %eax)
17258       (write-buffered *(ebp+8) ":break:\n")
17259     }
17260 $emit-subx-block:end:
17261     # . restore registers
17262     5e/pop-to-esi
17263     59/pop-to-ecx
17264     58/pop-to-eax
17265     # . epilogue
17266     89/<- %esp 5/r32/ebp
17267     5d/pop-to-ebp
17268     c3/return
17269 
17270 # Primitives supported
17271 # See mu_instructions for a summary of this linked-list data structure.
17272 #
17273 # For each operation, put variants with hard-coded registers before flexible ones.
17274 #
17275 # Unfortunately, our restrictions on addresses require that various fields in
17276 # primitives be handles, which complicates these definitions.
17277 #   - we need to insert dummy fields all over the place for fake alloc-ids
17278 #   - we can't use our syntax sugar of quoted literals for string fields
17279 #
17280 # Fake alloc-ids are needed because our type definitions up top require
17281 # handles but it's clearer to statically allocate these long-lived objects.
17282 # Fake alloc-ids are perfectly safe, but they can't be reclaimed.
17283 #
17284 # Every 'object' below starts with a fake alloc-id. It may also contain other
17285 # fake alloc-ids for various handle fields.
17286 #
17287 # I think of objects starting with a fake alloc-id as having type 'payload'.
17288 # It's not really intended to be created dynamically; for that use `allocate`
17289 # as usual.
17290 #
17291 # Idea for a notation to simplify such definitions:
17292 #   _Primitive-increment-eax:  # (payload primitive)
17293 #     0x11/alloc-id:fake:payload
17294 #     0x11 @(0x11 "increment")  # name
17295 #     0 0                       # inouts
17296 #     0x11 @(0x11/payload
17297 #            0x11 @(0x11/payload  # List-value
17298 #                   0 0             # Var-name
17299 #                   0x11 @(0x11     # Var-type
17300 #                          1/is-atom
17301 #                          1/value 0/unused   # Type-tree-left
17302 #                          0 0                # Type-tree-right
17303 #                         )
17304 #                   1               # block-depth
17305 #                   0               # stack-offset
17306 #                   0x11 @(0x11 "eax")  # Var-register
17307 #                  )
17308 #            0 0)                 # List-next
17309 #     ...
17310 #     _Primitive-increment-ecx/imm32/next
17311 #   ...
17312 # Awfully complex and non-obvious. But also clearly signals there's something
17313 # to learn here, so may be worth trying.
17314 #
17315 # '@' is just an initial thought. Punctuation used so far in Mu: () * % # / "
17316 #
17317 # For now we'll continue to just use comments and manually ensure they stay up
17318 # to date.
17319 == data
17320 Primitives:  # (addr primitive)
17321 # - increment/decrement
17322 _Primitive-increment-eax:  # (addr primitive)
17323     # var/eax <- increment => 40/increment-eax
17324     0x11/imm32/alloc-id:fake
17325     _string-increment/imm32/name
17326     0/imm32/no-inouts
17327     0/imm32/no-inouts
17328     0x11/imm32/alloc-id:fake
17329     Single-int-var-in-eax/imm32/outputs
17330     0x11/imm32/alloc-id:fake
17331     _string_40_increment_eax/imm32/subx-name
17332     0/imm32/no-rm32
17333     0/imm32/no-r32
17334     0/imm32/no-imm32
17335     0/imm32/no-imm8
17336     0/imm32/no-disp32
17337     0/imm32/output-is-write-only
17338     0x11/imm32/alloc-id:fake
17339     _Primitive-increment-ecx/imm32/next
17340 _Primitive-increment-ecx:  # (payload primitive)
17341     0x11/imm32/alloc-id:fake:payload
17342     # var/ecx <- increment => 41/increment-ecx
17343     0x11/imm32/alloc-id:fake
17344     _string-increment/imm32/name
17345     0/imm32/no-inouts
17346     0/imm32/no-inouts
17347     0x11/imm32/alloc-id:fake
17348     Single-int-var-in-ecx/imm32/outputs
17349     0x11/imm32/alloc-id:fake
17350     _string_41_increment_ecx/imm32/subx-name
17351     0/imm32/no-rm32
17352     0/imm32/no-r32
17353     0/imm32/no-imm32
17354     0/imm32/no-imm8
17355     0/imm32/no-disp32
17356     0/imm32/output-is-write-only
17357     0x11/imm32/alloc-id:fake
17358     _Primitive-increment-edx/imm32/next
17359 _Primitive-increment-edx:  # (payload primitive)
17360     0x11/imm32/alloc-id:fake:payload
17361     # var/edx <- increment => 42/increment-edx
17362     0x11/imm32/alloc-id:fake
17363     _string-increment/imm32/name
17364     0/imm32/no-inouts
17365     0/imm32/no-inouts
17366     0x11/imm32/alloc-id:fake
17367     Single-int-var-in-edx/imm32/outputs
17368     0x11/imm32/alloc-id:fake
17369     _string_42_increment_edx/imm32/subx-name
17370     0/imm32/no-rm32
17371     0/imm32/no-r32
17372     0/imm32/no-imm32
17373     0/imm32/no-imm8
17374     0/imm32/no-disp32
17375     0/imm32/output-is-write-only
17376     0x11/imm32/alloc-id:fake
17377     _Primitive-increment-ebx/imm32/next
17378 _Primitive-increment-ebx:  # (payload primitive)
17379     0x11/imm32/alloc-id:fake:payload
17380     # var/ebx <- increment => 43/increment-ebx
17381     0x11/imm32/alloc-id:fake
17382     _string-increment/imm32/name
17383     0/imm32/no-inouts
17384     0/imm32/no-inouts
17385     0x11/imm32/alloc-id:fake
17386     Single-int-var-in-ebx/imm32/outputs
17387     0x11/imm32/alloc-id:fake
17388     _string_43_increment_ebx/imm32/subx-name
17389     0/imm32/no-rm32
17390     0/imm32/no-r32
17391     0/imm32/no-imm32
17392     0/imm32/no-imm8
17393     0/imm32/no-disp32
17394     0/imm32/output-is-write-only
17395     0x11/imm32/alloc-id:fake
17396     _Primitive-increment-esi/imm32/next
17397 _Primitive-increment-esi:  # (payload primitive)
17398     0x11/imm32/alloc-id:fake:payload
17399     # var/esi <- increment => 46/increment-esi
17400     0x11/imm32/alloc-id:fake
17401     _string-increment/imm32/name
17402     0/imm32/no-inouts
17403     0/imm32/no-inouts
17404     0x11/imm32/alloc-id:fake
17405     Single-int-var-in-esi/imm32/outputs
17406     0x11/imm32/alloc-id:fake
17407     _string_46_increment_esi/imm32/subx-name
17408     0/imm32/no-rm32
17409     0/imm32/no-r32
17410     0/imm32/no-imm32
17411     0/imm32/no-imm8
17412     0/imm32/no-disp32
17413     0/imm32/output-is-write-only
17414     0x11/imm32/alloc-id:fake
17415     _Primitive-increment-edi/imm32/next
17416 _Primitive-increment-edi:  # (payload primitive)
17417     0x11/imm32/alloc-id:fake:payload
17418     # var/edi <- increment => 47/increment-edi
17419     0x11/imm32/alloc-id:fake
17420     _string-increment/imm32/name
17421     0/imm32/no-inouts
17422     0/imm32/no-inouts
17423     0x11/imm32/alloc-id:fake
17424     Single-int-var-in-edi/imm32/outputs
17425     0x11/imm32/alloc-id:fake
17426     _string_47_increment_edi/imm32/subx-name
17427     0/imm32/no-rm32
17428     0/imm32/no-r32
17429     0/imm32/no-imm32
17430     0/imm32/no-imm8
17431     0/imm32/no-disp32
17432     0/imm32/output-is-write-only
17433     0x11/imm32/alloc-id:fake
17434     _Primitive-decrement-eax/imm32/next
17435 _Primitive-decrement-eax:  # (payload primitive)
17436     0x11/imm32/alloc-id:fake:payload
17437     # var/eax <- decrement => 48/decrement-eax
17438     0x11/imm32/alloc-id:fake
17439     _string-decrement/imm32/name
17440     0/imm32/no-inouts
17441     0/imm32/no-inouts
17442     0x11/imm32/alloc-id:fake
17443     Single-int-var-in-eax/imm32/outputs
17444     0x11/imm32/alloc-id:fake
17445     _string_48_decrement_eax/imm32/subx-name
17446     0/imm32/no-rm32
17447     0/imm32/no-r32
17448     0/imm32/no-imm32
17449     0/imm32/no-imm8
17450     0/imm32/no-disp32
17451     0/imm32/output-is-write-only
17452     0x11/imm32/alloc-id:fake
17453     _Primitive-decrement-ecx/imm32/next
17454 _Primitive-decrement-ecx:  # (payload primitive)
17455     0x11/imm32/alloc-id:fake:payload
17456     # var/ecx <- decrement => 49/decrement-ecx
17457     0x11/imm32/alloc-id:fake
17458     _string-decrement/imm32/name
17459     0/imm32/no-inouts
17460     0/imm32/no-inouts
17461     0x11/imm32/alloc-id:fake
17462     Single-int-var-in-ecx/imm32/outputs
17463     0x11/imm32/alloc-id:fake
17464     _string_49_decrement_ecx/imm32/subx-name
17465     0/imm32/no-rm32
17466     0/imm32/no-r32
17467     0/imm32/no-imm32
17468     0/imm32/no-imm8
17469     0/imm32/no-disp32
17470     0/imm32/output-is-write-only
17471     0x11/imm32/alloc-id:fake
17472     _Primitive-decrement-edx/imm32/next
17473 _Primitive-decrement-edx:  # (payload primitive)
17474     0x11/imm32/alloc-id:fake:payload
17475     # var/edx <- decrement => 4a/decrement-edx
17476     0x11/imm32/alloc-id:fake
17477     _string-decrement/imm32/name
17478     0/imm32/no-inouts
17479     0/imm32/no-inouts
17480     0x11/imm32/alloc-id:fake
17481     Single-int-var-in-edx/imm32/outputs
17482     0x11/imm32/alloc-id:fake
17483     _string_4a_decrement_edx/imm32/subx-name
17484     0/imm32/no-rm32
17485     0/imm32/no-r32
17486     0/imm32/no-imm32
17487     0/imm32/no-imm8
17488     0/imm32/no-disp32
17489     0/imm32/output-is-write-only
17490     0x11/imm32/alloc-id:fake
17491     _Primitive-decrement-ebx/imm32/next
17492 _Primitive-decrement-ebx:  # (payload primitive)
17493     0x11/imm32/alloc-id:fake:payload
17494     # var/ebx <- decrement => 4b/decrement-ebx
17495     0x11/imm32/alloc-id:fake
17496     _string-decrement/imm32/name
17497     0/imm32/no-inouts
17498     0/imm32/no-inouts
17499     0x11/imm32/alloc-id:fake
17500     Single-int-var-in-ebx/imm32/outputs
17501     0x11/imm32/alloc-id:fake
17502     _string_4b_decrement_ebx/imm32/subx-name
17503     0/imm32/no-rm32
17504     0/imm32/no-r32
17505     0/imm32/no-imm32
17506     0/imm32/no-imm8
17507     0/imm32/no-disp32
17508     0/imm32/output-is-write-only
17509     0x11/imm32/alloc-id:fake
17510     _Primitive-decrement-esi/imm32/next
17511 _Primitive-decrement-esi:  # (payload primitive)
17512     0x11/imm32/alloc-id:fake:payload
17513     # var/esi <- decrement => 4e/decrement-esi
17514     0x11/imm32/alloc-id:fake
17515     _string-decrement/imm32/name
17516     0/imm32/no-inouts
17517     0/imm32/no-inouts
17518     0x11/imm32/alloc-id:fake
17519     Single-int-var-in-esi/imm32/outputs
17520     0x11/imm32/alloc-id:fake
17521     _string_4e_decrement_esi/imm32/subx-name
17522     0/imm32/no-rm32
17523     0/imm32/no-r32
17524     0/imm32/no-imm32
17525     0/imm32/no-imm8
17526     0/imm32/no-disp32
17527     0/imm32/output-is-write-only
17528     0x11/imm32/alloc-id:fake
17529     _Primitive-decrement-edi/imm32/next
17530 _Primitive-decrement-edi:  # (payload primitive)
17531     0x11/imm32/alloc-id:fake:payload
17532     # var/edi <- decrement => 4f/decrement-edi
17533     0x11/imm32/alloc-id:fake
17534     _string-decrement/imm32/name
17535     0/imm32/no-inouts
17536     0/imm32/no-inouts
17537     0x11/imm32/alloc-id:fake
17538     Single-int-var-in-edi/imm32/outputs
17539     0x11/imm32/alloc-id:fake
17540     _string_4f_decrement_edi/imm32/subx-name
17541     0/imm32/no-rm32
17542     0/imm32/no-r32
17543     0/imm32/no-imm32
17544     0/imm32/no-imm8
17545     0/imm32/no-disp32
17546     0/imm32/output-is-write-only
17547     0x11/imm32/alloc-id:fake
17548     _Primitive-increment-mem/imm32/next
17549 _Primitive-increment-mem:  # (payload primitive)
17550     0x11/imm32/alloc-id:fake:payload
17551     # increment var => ff 0/subop/increment *(ebp+__)
17552     0x11/imm32/alloc-id:fake
17553     _string-increment/imm32/name
17554     0x11/imm32/alloc-id:fake
17555     Single-int-var-in-mem/imm32/inouts
17556     0/imm32/no-outputs
17557     0/imm32/no-outputs
17558     0x11/imm32/alloc-id:fake
17559     _string_ff_subop_increment/imm32/subx-name
17560     1/imm32/rm32-is-first-inout
17561     0/imm32/no-r32
17562     0/imm32/no-imm32
17563     0/imm32/no-imm8
17564     0/imm32/no-disp32
17565     0/imm32/output-is-write-only
17566     0x11/imm32/alloc-id:fake
17567     _Primitive-increment-reg/imm32/next
17568 _Primitive-increment-reg:  # (payload primitive)
17569     0x11/imm32/alloc-id:fake:payload
17570     # var/reg <- increment => ff 0/subop/increment %__
17571     0x11/imm32/alloc-id:fake
17572     _string-increment/imm32/name
17573     0/imm32/no-inouts
17574     0/imm32/no-inouts
17575     0x11/imm32/alloc-id:fake
17576     Single-int-var-in-some-register/imm32/outputs
17577     0x11/imm32/alloc-id:fake
17578     _string_ff_subop_increment/imm32/subx-name
17579     3/imm32/rm32-is-first-output
17580     0/imm32/no-r32
17581     0/imm32/no-imm32
17582     0/imm32/no-imm8
17583     0/imm32/no-disp32
17584     0/imm32/output-is-write-only
17585     0x11/imm32/alloc-id:fake
17586     _Primitive-decrement-mem/imm32/next
17587 _Primitive-decrement-mem:  # (payload primitive)
17588     0x11/imm32/alloc-id:fake:payload
17589     # decrement var => ff 1/subop/decrement *(ebp+__)
17590     0x11/imm32/alloc-id:fake
17591     _string-decrement/imm32/name
17592     0x11/imm32/alloc-id:fake
17593     Single-int-var-in-mem/imm32/inouts
17594     0/imm32/no-outputs
17595     0/imm32/no-outputs
17596     0x11/imm32/alloc-id:fake
17597     _string_ff_subop_decrement/imm32/subx-name
17598     1/imm32/rm32-is-first-inout
17599     0/imm32/no-r32
17600     0/imm32/no-imm32
17601     0/imm32/no-imm8
17602     0/imm32/no-disp32
17603     0/imm32/output-is-write-only
17604     0x11/imm32/alloc-id:fake
17605     _Primitive-decrement-reg/imm32/next
17606 _Primitive-decrement-reg:  # (payload primitive)
17607     0x11/imm32/alloc-id:fake:payload
17608     # var/reg <- decrement => ff 1/subop/decrement %__
17609     0x11/imm32/alloc-id:fake
17610     _string-decrement/imm32/name
17611     0/imm32/no-inouts
17612     0/imm32/no-inouts
17613     0x11/imm32/alloc-id:fake
17614     Single-int-var-in-some-register/imm32/outputs
17615     0x11/imm32/alloc-id:fake
17616     _string_ff_subop_decrement/imm32/subx-name
17617     3/imm32/rm32-is-first-output
17618     0/imm32/no-r32
17619     0/imm32/no-imm32
17620     0/imm32/no-imm8
17621     0/imm32/no-disp32
17622     0/imm32/output-is-write-only
17623     0x11/imm32/alloc-id:fake
17624     _Primitive-add-to-eax/imm32/next
17625 # - add
17626 _Primitive-add-to-eax:  # (payload primitive)
17627     0x11/imm32/alloc-id:fake:payload
17628     # var/eax <- add lit => 05/add-to-eax lit/imm32
17629     0x11/imm32/alloc-id:fake
17630     _string-add/imm32/name
17631     0x11/imm32/alloc-id:fake
17632     Single-lit-var/imm32/inouts
17633     0x11/imm32/alloc-id:fake
17634     Single-int-var-in-eax/imm32/outputs
17635     0x11/imm32/alloc-id:fake
17636     _string_05_add_to_eax/imm32/subx-name
17637     0/imm32/no-rm32
17638     0/imm32/no-r32
17639     1/imm32/imm32-is-first-inout
17640     0/imm32/no-imm8
17641     0/imm32/no-disp32
17642     0/imm32/output-is-write-only
17643     0x11/imm32/alloc-id:fake
17644     _Primitive-add-reg-to-reg/imm32/next
17645 _Primitive-add-reg-to-reg:  # (payload primitive)
17646     0x11/imm32/alloc-id:fake:payload
17647     # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32
17648     0x11/imm32/alloc-id:fake
17649     _string-add/imm32/name
17650     0x11/imm32/alloc-id:fake
17651     Single-int-var-in-some-register/imm32/inouts
17652     0x11/imm32/alloc-id:fake
17653     Single-int-var-in-some-register/imm32/outputs
17654     0x11/imm32/alloc-id:fake
17655     _string_01_add_to/imm32/subx-name
17656     3/imm32/rm32-is-first-output
17657     1/imm32/r32-is-first-inout
17658     0/imm32/no-imm32
17659     0/imm32/no-imm8
17660     0/imm32/no-disp32
17661     0/imm32/output-is-write-only
17662     0x11/imm32/alloc-id:fake
17663     _Primitive-add-reg-to-mem/imm32/next
17664 _Primitive-add-reg-to-mem:  # (payload primitive)
17665     0x11/imm32/alloc-id:fake:payload
17666     # add-to var1 var2/reg => 01/add-to var1 var2/r32
17667     0x11/imm32/alloc-id:fake
17668     _string-add-to/imm32/name
17669     0x11/imm32/alloc-id:fake
17670     Two-args-int-stack-int-reg/imm32/inouts
17671     0/imm32/no-outputs
17672     0/imm32/no-outputs
17673     0x11/imm32/alloc-id:fake
17674     _string_01_add_to/imm32/subx-name
17675     1/imm32/rm32-is-first-inout
17676     2/imm32/r32-is-second-inout
17677     0/imm32/no-imm32
17678     0/imm32/no-imm8
17679     0/imm32/no-disp32
17680     0/imm32/output-is-write-only
17681     0x11/imm32/alloc-id:fake
17682     _Primitive-add-mem-to-reg/imm32/next
17683 _Primitive-add-mem-to-reg:  # (payload primitive)
17684     0x11/imm32/alloc-id:fake:payload
17685     # var1/reg <- add var2 => 03/add var2/rm32 var1/r32
17686     0x11/imm32/alloc-id:fake
17687     _string-add/imm32/name
17688     0x11/imm32/alloc-id:fake
17689     Single-int-var-in-mem/imm32/inouts
17690     0x11/imm32/alloc-id:fake
17691     Single-int-var-in-some-register/imm32/outputs
17692     0x11/imm32/alloc-id:fake
17693     _string_03_add/imm32/subx-name
17694     1/imm32/rm32-is-first-inout
17695     3/imm32/r32-is-first-output
17696     0/imm32/no-imm32
17697     0/imm32/no-imm8
17698     0/imm32/no-disp32
17699     0/imm32/output-is-write-only
17700     0x11/imm32/alloc-id:fake
17701     _Primitive-add-lit-to-reg/imm32/next
17702 _Primitive-add-lit-to-reg:  # (payload primitive)
17703     0x11/imm32/alloc-id:fake:payload
17704     # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32
17705     0x11/imm32/alloc-id:fake
17706     _string-add/imm32/name
17707     0x11/imm32/alloc-id:fake
17708     Single-lit-var/imm32/inouts
17709     0x11/imm32/alloc-id:fake
17710     Single-int-var-in-some-register/imm32/outputs
17711     0x11/imm32/alloc-id:fake
17712     _string_81_subop_add/imm32/subx-name
17713     3/imm32/rm32-is-first-output
17714     0/imm32/no-r32
17715     1/imm32/imm32-is-first-inout
17716     0/imm32/no-imm8
17717     0/imm32/no-disp32
17718     0/imm32/output-is-write-only
17719     0x11/imm32/alloc-id:fake
17720     _Primitive-add-lit-to-mem/imm32/next
17721 _Primitive-add-lit-to-mem:  # (payload primitive)
17722     0x11/imm32/alloc-id:fake:payload
17723     # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32
17724     0x11/imm32/alloc-id:fake
17725     _string-add-to/imm32/name
17726     0x11/imm32/alloc-id:fake
17727     Int-var-and-literal/imm32/inouts
17728     0/imm32/no-outputs
17729     0/imm32/no-outputs
17730     0x11/imm32/alloc-id:fake
17731     _string_81_subop_add/imm32/subx-name
17732     1/imm32/rm32-is-first-inout
17733     0/imm32/no-r32
17734     2/imm32/imm32-is-second-inout
17735     0/imm32/no-imm8
17736     0/imm32/no-disp32
17737     0/imm32/output-is-write-only
17738     0x11/imm32/alloc-id:fake
17739     _Primitive-subtract-from-eax/imm32/next
17740 # - subtract
17741 _Primitive-subtract-from-eax:  # (payload primitive)
17742     0x11/imm32/alloc-id:fake:payload
17743     # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32
17744     0x11/imm32/alloc-id:fake
17745     _string-subtract/imm32/name
17746     0x11/imm32/alloc-id:fake
17747     Single-lit-var/imm32/inouts
17748     0x11/imm32/alloc-id:fake
17749     Single-int-var-in-eax/imm32/outputs
17750     0x11/imm32/alloc-id:fake
17751     _string_2d_subtract_from_eax/imm32/subx-name
17752     0/imm32/no-rm32
17753     0/imm32/no-r32
17754     1/imm32/imm32-is-first-inout
17755     0/imm32/no-imm8
17756     0/imm32/no-disp32
17757     0/imm32/output-is-write-only
17758     0x11/imm32/alloc-id:fake
17759     _Primitive-subtract-reg-from-reg/imm32/next
17760 _Primitive-subtract-reg-from-reg:  # (payload primitive)
17761     0x11/imm32/alloc-id:fake:payload
17762     # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32
17763     0x11/imm32/alloc-id:fake
17764     _string-subtract/imm32/name
17765     0x11/imm32/alloc-id:fake
17766     Single-int-var-in-some-register/imm32/inouts
17767     0x11/imm32/alloc-id:fake
17768     Single-int-var-in-some-register/imm32/outputs
17769     0x11/imm32/alloc-id:fake
17770     _string_29_subtract_from/imm32/subx-name
17771     3/imm32/rm32-is-first-output
17772     1/imm32/r32-is-first-inout
17773     0/imm32/no-imm32
17774     0/imm32/no-imm8
17775     0/imm32/no-disp32
17776     0/imm32/output-is-write-only
17777     0x11/imm32/alloc-id:fake
17778     _Primitive-subtract-reg-from-mem/imm32/next
17779 _Primitive-subtract-reg-from-mem:  # (payload primitive)
17780     0x11/imm32/alloc-id:fake:payload
17781     # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32
17782     0x11/imm32/alloc-id:fake
17783     _string-subtract-from/imm32/name
17784     0x11/imm32/alloc-id:fake
17785     Two-args-int-stack-int-reg/imm32/inouts
17786     0/imm32/no-outputs
17787     0/imm32/no-outputs
17788     0x11/imm32/alloc-id:fake
17789     _string_29_subtract_from/imm32/subx-name
17790     1/imm32/rm32-is-first-inout
17791     2/imm32/r32-is-second-inout
17792     0/imm32/no-imm32
17793     0/imm32/no-imm8
17794     0/imm32/no-disp32
17795     0/imm32/output-is-write-only
17796     0x11/imm32/alloc-id:fake
17797     _Primitive-subtract-mem-from-reg/imm32/next
17798 _Primitive-subtract-mem-from-reg:  # (payload primitive)
17799     0x11/imm32/alloc-id:fake:payload
17800     # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32
17801     0x11/imm32/alloc-id:fake
17802     _string-subtract/imm32/name
17803     0x11/imm32/alloc-id:fake
17804     Single-int-var-in-mem/imm32/inouts
17805     0x11/imm32/alloc-id:fake
17806     Single-int-var-in-some-register/imm32/outputs
17807     0x11/imm32/alloc-id:fake
17808     _string_2b_subtract/imm32/subx-name
17809     1/imm32/rm32-is-first-inout
17810     3/imm32/r32-is-first-output
17811     0/imm32/no-imm32
17812     0/imm32/no-imm8
17813     0/imm32/no-disp32
17814     0/imm32/output-is-write-only
17815     0x11/imm32/alloc-id:fake
17816     _Primitive-subtract-lit-from-reg/imm32/next
17817 _Primitive-subtract-lit-from-reg:  # (payload primitive)
17818     0x11/imm32/alloc-id:fake:payload
17819     # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32
17820     0x11/imm32/alloc-id:fake
17821     _string-subtract/imm32/name
17822     0x11/imm32/alloc-id:fake
17823     Single-lit-var/imm32/inouts
17824     0x11/imm32/alloc-id:fake
17825     Single-int-var-in-some-register/imm32/outputs
17826     0x11/imm32/alloc-id:fake
17827     _string_81_subop_subtract/imm32/subx-name
17828     3/imm32/rm32-is-first-output
17829     0/imm32/no-r32
17830     1/imm32/imm32-is-first-inout
17831     0/imm32/no-imm8
17832     0/imm32/no-disp32
17833     0/imm32/output-is-write-only
17834     0x11/imm32/alloc-id:fake
17835     _Primitive-subtract-lit-from-mem/imm32/next
17836 _Primitive-subtract-lit-from-mem:  # (payload primitive)
17837     0x11/imm32/alloc-id:fake:payload
17838     # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32
17839     0x11/imm32/alloc-id:fake
17840     _string-subtract-from/imm32/name
17841     0x11/imm32/alloc-id:fake
17842     Int-var-and-literal/imm32/inouts
17843     0/imm32/no-outputs
17844     0/imm32/no-outputs
17845     0x11/imm32/alloc-id:fake
17846     _string_81_subop_subtract/imm32/subx-name
17847     1/imm32/rm32-is-first-inout
17848     0/imm32/no-r32
17849     2/imm32/imm32-is-second-inout
17850     0/imm32/no-imm8
17851     0/imm32/no-disp32
17852     0/imm32/output-is-write-only
17853     0x11/imm32/alloc-id:fake
17854     _Primitive-and-with-eax/imm32/next
17855 # - and
17856 _Primitive-and-with-eax:  # (payload primitive)
17857     0x11/imm32/alloc-id:fake:payload
17858     # var/eax <- and lit => 25/and-with-eax lit/imm32
17859     0x11/imm32/alloc-id:fake
17860     _string-and/imm32/name
17861     0x11/imm32/alloc-id:fake
17862     Single-lit-var/imm32/inouts
17863     0x11/imm32/alloc-id:fake
17864     Single-int-var-in-eax/imm32/outputs
17865     0x11/imm32/alloc-id:fake
17866     _string_25_and_with_eax/imm32/subx-name
17867     0/imm32/no-rm32
17868     0/imm32/no-r32
17869     1/imm32/imm32-is-first-inout
17870     0/imm32/no-imm8
17871     0/imm32/no-disp32
17872     0/imm32/output-is-write-only
17873     0x11/imm32/alloc-id:fake
17874     _Primitive-and-reg-with-reg/imm32/next
17875 _Primitive-and-reg-with-reg:  # (payload primitive)
17876     0x11/imm32/alloc-id:fake:payload
17877     # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32
17878     0x11/imm32/alloc-id:fake
17879     _string-and/imm32/name
17880     0x11/imm32/alloc-id:fake
17881     Single-int-var-in-some-register/imm32/inouts
17882     0x11/imm32/alloc-id:fake
17883     Single-int-var-in-some-register/imm32/outputs
17884     0x11/imm32/alloc-id:fake
17885     _string_21_and_with/imm32/subx-name
17886     3/imm32/rm32-is-first-output
17887     1/imm32/r32-is-first-inout
17888     0/imm32/no-imm32
17889     0/imm32/no-imm8
17890     0/imm32/no-disp32
17891     0/imm32/output-is-write-only
17892     0x11/imm32/alloc-id:fake
17893     _Primitive-and-reg-with-mem/imm32/next
17894 _Primitive-and-reg-with-mem:  # (payload primitive)
17895     0x11/imm32/alloc-id:fake:payload
17896     # and-with var1 var2/reg => 21/and-with var1 var2/r32
17897     0x11/imm32/alloc-id:fake
17898     _string-and-with/imm32/name
17899     0x11/imm32/alloc-id:fake
17900     Two-args-int-stack-int-reg/imm32/inouts
17901     0/imm32/no-outputs
17902     0/imm32/no-outputs
17903     0x11/imm32/alloc-id:fake
17904     _string_21_and_with/imm32/subx-name
17905     1/imm32/rm32-is-first-inout
17906     2/imm32/r32-is-second-inout
17907     0/imm32/no-imm32
17908     0/imm32/no-imm8
17909     0/imm32/no-disp32
17910     0/imm32/output-is-write-only
17911     0x11/imm32/alloc-id:fake
17912     _Primitive-and-mem-with-reg/imm32/next
17913 _Primitive-and-mem-with-reg:  # (payload primitive)
17914     0x11/imm32/alloc-id:fake:payload
17915     # var1/reg <- and var2 => 23/and var2/rm32 var1/r32
17916     0x11/imm32/alloc-id:fake
17917     _string-and/imm32/name
17918     0x11/imm32/alloc-id:fake
17919     Single-int-var-in-mem/imm32/inouts
17920     0x11/imm32/alloc-id:fake
17921     Single-int-var-in-some-register/imm32/outputs
17922     0x11/imm32/alloc-id:fake
17923     _string_23_and/imm32/subx-name
17924     1/imm32/rm32-is-first-inout
17925     3/imm32/r32-is-first-output
17926     0/imm32/no-imm32
17927     0/imm32/no-imm8
17928     0/imm32/no-disp32
17929     0/imm32/output-is-write-only
17930     0x11/imm32/alloc-id:fake
17931     _Primitive-and-lit-with-reg/imm32/next
17932 _Primitive-and-lit-with-reg:  # (payload primitive)
17933     0x11/imm32/alloc-id:fake:payload
17934     # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32
17935     0x11/imm32/alloc-id:fake
17936     _string-and/imm32/name
17937     0x11/imm32/alloc-id:fake
17938     Single-lit-var/imm32/inouts
17939     0x11/imm32/alloc-id:fake
17940     Single-int-var-in-some-register/imm32/outputs
17941     0x11/imm32/alloc-id:fake
17942     _string_81_subop_and/imm32/subx-name
17943     3/imm32/rm32-is-first-output
17944     0/imm32/no-r32
17945     1/imm32/imm32-is-first-inout
17946     0/imm32/no-imm8
17947     0/imm32/no-disp32
17948     0/imm32/output-is-write-only
17949     0x11/imm32/alloc-id:fake
17950     _Primitive-and-lit-with-mem/imm32/next
17951 _Primitive-and-lit-with-mem:  # (payload primitive)
17952     0x11/imm32/alloc-id:fake:payload
17953     # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32
17954     0x11/imm32/alloc-id:fake
17955     _string-and-with/imm32/name
17956     0x11/imm32/alloc-id:fake
17957     Int-var-and-literal/imm32/inouts
17958     0/imm32/no-outputs
17959     0/imm32/no-outputs
17960     0x11/imm32/alloc-id:fake
17961     _string_81_subop_and/imm32/subx-name
17962     1/imm32/rm32-is-first-inout
17963     0/imm32/no-r32
17964     2/imm32/imm32-is-second-inout
17965     0/imm32/no-imm8
17966     0/imm32/no-disp32
17967     0/imm32/output-is-write-only
17968     0x11/imm32/alloc-id:fake
17969     _Primitive-or-with-eax/imm32/next
17970 # - or
17971 _Primitive-or-with-eax:  # (payload primitive)
17972     0x11/imm32/alloc-id:fake:payload
17973     # var/eax <- or lit => 0d/or-with-eax lit/imm32
17974     0x11/imm32/alloc-id:fake
17975     _string-or/imm32/name
17976     0x11/imm32/alloc-id:fake
17977     Single-lit-var/imm32/inouts
17978     0x11/imm32/alloc-id:fake
17979     Single-int-var-in-eax/imm32/outputs
17980     0x11/imm32/alloc-id:fake
17981     _string_0d_or_with_eax/imm32/subx-name
17982     0/imm32/no-rm32
17983     0/imm32/no-r32
17984     1/imm32/imm32-is-first-inout
17985     0/imm32/no-imm8
17986     0/imm32/no-disp32
17987     0/imm32/output-is-write-only
17988     0x11/imm32/alloc-id:fake
17989     _Primitive-or-reg-with-reg/imm32/next
17990 _Primitive-or-reg-with-reg:  # (payload primitive)
17991     0x11/imm32/alloc-id:fake:payload
17992     # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32
17993     0x11/imm32/alloc-id:fake
17994     _string-or/imm32/name
17995     0x11/imm32/alloc-id:fake
17996     Single-int-var-in-some-register/imm32/inouts
17997     0x11/imm32/alloc-id:fake
17998     Single-int-var-in-some-register/imm32/outputs
17999     0x11/imm32/alloc-id:fake
18000     _string_09_or_with/imm32/subx-name
18001     3/imm32/rm32-is-first-output
18002     1/imm32/r32-is-first-inout
18003     0/imm32/no-imm32
18004     0/imm32/no-imm8
18005     0/imm32/no-disp32
18006     0/imm32/output-is-write-only
18007     0x11/imm32/alloc-id:fake
18008     _Primitive-or-reg-with-mem/imm32/next
18009 _Primitive-or-reg-with-mem:  # (payload primitive)
18010     0x11/imm32/alloc-id:fake:payload
18011     # or-with var1 var2/reg => 09/or-with var1 var2/r32
18012     0x11/imm32/alloc-id:fake
18013     _string-or-with/imm32/name
18014     0x11/imm32/alloc-id:fake
18015     Two-args-int-stack-int-reg/imm32/inouts
18016     0/imm32/no-outputs
18017     0/imm32/no-outputs
18018     0x11/imm32/alloc-id:fake
18019     _string_09_or_with/imm32/subx-name
18020     1/imm32/rm32-is-first-inout
18021     2/imm32/r32-is-second-inout
18022     0/imm32/no-imm32
18023     0/imm32/no-imm8
18024     0/imm32/no-disp32
18025     0/imm32/output-is-write-only
18026     0x11/imm32/alloc-id:fake
18027     _Primitive-or-mem-with-reg/imm32/next
18028 _Primitive-or-mem-with-reg:  # (payload primitive)
18029     0x11/imm32/alloc-id:fake:payload
18030     # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32
18031     0x11/imm32/alloc-id:fake
18032     _string-or/imm32/name
18033     0x11/imm32/alloc-id:fake
18034     Single-int-var-in-mem/imm32/inouts
18035     0x11/imm32/alloc-id:fake
18036     Single-int-var-in-some-register/imm32/outputs
18037     0x11/imm32/alloc-id:fake
18038     _string_0b_or/imm32/subx-name
18039     1/imm32/rm32-is-first-inout
18040     3/imm32/r32-is-first-output
18041     0/imm32/no-imm32
18042     0/imm32/no-imm8
18043     0/imm32/no-disp32
18044     0/imm32/output-is-write-only
18045     0x11/imm32/alloc-id:fake
18046     _Primitive-or-lit-with-reg/imm32/next
18047 _Primitive-or-lit-with-reg:  # (payload primitive)
18048     0x11/imm32/alloc-id:fake:payload
18049     # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32
18050     0x11/imm32/alloc-id:fake
18051     _string-or/imm32/name
18052     0x11/imm32/alloc-id:fake
18053     Single-lit-var/imm32/inouts
18054     0x11/imm32/alloc-id:fake
18055     Single-int-var-in-some-register/imm32/outputs
18056     0x11/imm32/alloc-id:fake
18057     _string_81_subop_or/imm32/subx-name
18058     3/imm32/rm32-is-first-output
18059     0/imm32/no-r32
18060     1/imm32/imm32-is-first-inout
18061     0/imm32/no-imm8
18062     0/imm32/no-disp32
18063     0/imm32/output-is-write-only
18064     0x11/imm32/alloc-id:fake
18065     _Primitive-or-lit-with-mem/imm32/next
18066 _Primitive-or-lit-with-mem:  # (payload primitive)
18067     0x11/imm32/alloc-id:fake:payload
18068     # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32
18069     0x11/imm32/alloc-id:fake
18070     _string-or-with/imm32/name
18071     0x11/imm32/alloc-id:fake
18072     Int-var-and-literal/imm32/inouts
18073     0/imm32/no-outputs
18074     0/imm32/no-outputs
18075     0x11/imm32/alloc-id:fake
18076     _string_81_subop_or/imm32/subx-name
18077     1/imm32/rm32-is-first-inout
18078     0/imm32/no-r32
18079     2/imm32/imm32-is-second-inout
18080     0/imm32/no-imm8
18081     0/imm32/no-disp32
18082     0/imm32/output-is-write-only
18083     0x11/imm32/alloc-id:fake
18084     _Primitive-xor-with-eax/imm32/next
18085 # - xor
18086 _Primitive-xor-with-eax:  # (payload primitive)
18087     0x11/imm32/alloc-id:fake:payload
18088     # var/eax <- xor lit => 35/xor-with-eax lit/imm32
18089     0x11/imm32/alloc-id:fake
18090     _string-xor/imm32/name
18091     0x11/imm32/alloc-id:fake
18092     Single-lit-var/imm32/inouts
18093     0x11/imm32/alloc-id:fake
18094     Single-int-var-in-eax/imm32/outputs
18095     0x11/imm32/alloc-id:fake
18096     _string_35_xor_with_eax/imm32/subx-name
18097     0/imm32/no-rm32
18098     0/imm32/no-r32
18099     1/imm32/imm32-is-first-inout
18100     0/imm32/no-imm8
18101     0/imm32/no-disp32
18102     0/imm32/output-is-write-only
18103     0x11/imm32/alloc-id:fake
18104     _Primitive-xor-reg-with-reg/imm32/next
18105 _Primitive-xor-reg-with-reg:  # (payload primitive)
18106     0x11/imm32/alloc-id:fake:payload
18107     # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32
18108     0x11/imm32/alloc-id:fake
18109     _string-xor/imm32/name
18110     0x11/imm32/alloc-id:fake
18111     Single-int-var-in-some-register/imm32/inouts
18112     0x11/imm32/alloc-id:fake
18113     Single-int-var-in-some-register/imm32/outputs
18114     0x11/imm32/alloc-id:fake
18115     _string_31_xor_with/imm32/subx-name
18116     3/imm32/rm32-is-first-output
18117     1/imm32/r32-is-first-inout
18118     0/imm32/no-imm32
18119     0/imm32/no-imm8
18120     0/imm32/no-disp32
18121     0/imm32/output-is-write-only
18122     0x11/imm32/alloc-id:fake
18123     _Primitive-xor-reg-with-mem/imm32/next
18124 _Primitive-xor-reg-with-mem:  # (payload primitive)
18125     0x11/imm32/alloc-id:fake:payload
18126     # xor-with var1 var2/reg => 31/xor-with var1 var2/r32
18127     0x11/imm32/alloc-id:fake
18128     _string-xor-with/imm32/name
18129     0x11/imm32/alloc-id:fake
18130     Two-args-int-stack-int-reg/imm32/inouts
18131     0/imm32/no-outputs
18132     0/imm32/no-outputs
18133     0x11/imm32/alloc-id:fake
18134     _string_31_xor_with/imm32/subx-name
18135     1/imm32/rm32-is-first-inout
18136     2/imm32/r32-is-second-inout
18137     0/imm32/no-imm32
18138     0/imm32/no-imm8
18139     0/imm32/no-disp32
18140     0/imm32/output-is-write-only
18141     0x11/imm32/alloc-id:fake
18142     _Primitive-xor-mem-with-reg/imm32/next
18143 _Primitive-xor-mem-with-reg:  # (payload primitive)
18144     0x11/imm32/alloc-id:fake:payload
18145     # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32
18146     0x11/imm32/alloc-id:fake
18147     _string-xor/imm32/name
18148     0x11/imm32/alloc-id:fake
18149     Single-int-var-in-mem/imm32/inouts
18150     0x11/imm32/alloc-id:fake
18151     Single-int-var-in-some-register/imm32/outputs
18152     0x11/imm32/alloc-id:fake
18153     _string_33_xor/imm32/subx-name
18154     1/imm32/rm32-is-first-inout
18155     3/imm32/r32-is-first-output
18156     0/imm32/no-imm32
18157     0/imm32/no-imm8
18158     0/imm32/no-disp32
18159     0/imm32/output-is-write-only
18160     0x11/imm32/alloc-id:fake
18161     _Primitive-xor-lit-with-reg/imm32/next
18162 _Primitive-xor-lit-with-reg:  # (payload primitive)
18163     0x11/imm32/alloc-id:fake:payload
18164     # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32
18165     0x11/imm32/alloc-id:fake
18166     _string-xor/imm32/name
18167     0x11/imm32/alloc-id:fake
18168     Single-lit-var/imm32/inouts
18169     0x11/imm32/alloc-id:fake
18170     Single-int-var-in-some-register/imm32/outputs
18171     0x11/imm32/alloc-id:fake
18172     _string_81_subop_xor/imm32/subx-name
18173     3/imm32/rm32-is-first-output
18174     0/imm32/no-r32
18175     1/imm32/imm32-is-first-inout
18176     0/imm32/no-imm8
18177     0/imm32/no-disp32
18178     0/imm32/output-is-write-only
18179     0x11/imm32/alloc-id:fake
18180     _Primitive-xor-lit-with-mem/imm32/next
18181 _Primitive-xor-lit-with-mem:  # (payload primitive)
18182     0x11/imm32/alloc-id:fake:payload
18183     # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32
18184     0x11/imm32/alloc-id:fake
18185     _string-xor-with/imm32/name
18186     0x11/imm32/alloc-id:fake
18187     Int-var-and-literal/imm32/inouts
18188     0/imm32/no-outputs
18189     0/imm32/no-outputs
18190     0x11/imm32/alloc-id:fake
18191     _string_81_subop_xor/imm32/subx-name
18192     1/imm32/rm32-is-first-inout
18193     0/imm32/no-r32
18194     2/imm32/imm32-is-second-inout
18195     0/imm32/no-imm8
18196     0/imm32/no-disp32
18197     0/imm32/output-is-write-only
18198     0x11/imm32/alloc-id:fake
18199     _Primitive-shift-reg-left-by-lit/imm32/next
18200 _Primitive-shift-reg-left-by-lit:  # (payload primitive)
18201     0x11/imm32/alloc-id:fake:payload
18202     # var1/reg <- shift-left lit => c1/shift 4/subop/left var1/rm32 lit/imm32
18203     0x11/imm32/alloc-id:fake
18204     _string-shift-left/imm32/name
18205     0x11/imm32/alloc-id:fake
18206     Single-lit-var/imm32/inouts
18207     0x11/imm32/alloc-id:fake
18208     Single-int-var-in-some-register/imm32/outputs
18209     0x11/imm32/alloc-id:fake
18210     _string_c1_subop_shift_left/imm32/subx-name
18211     3/imm32/rm32-is-first-output
18212     0/imm32/no-r32
18213     0/imm32/no-imm32
18214     1/imm32/imm8-is-first-inout
18215     0/imm32/no-disp32
18216     0/imm32/output-is-write-only
18217     0x11/imm32/alloc-id:fake
18218     _Primitive-shift-reg-right-by-lit/imm32/next
18219 _Primitive-shift-reg-right-by-lit:  # (payload primitive)
18220     0x11/imm32/alloc-id:fake:payload
18221     # var1/reg <- shift-right lit => c1/shift 5/subop/right var1/rm32 lit/imm32
18222     0x11/imm32/alloc-id:fake
18223     _string-shift-right/imm32/name
18224     0x11/imm32/alloc-id:fake
18225     Single-lit-var/imm32/inouts
18226     0x11/imm32/alloc-id:fake
18227     Single-int-var-in-some-register/imm32/outputs
18228     0x11/imm32/alloc-id:fake
18229     _string_c1_subop_shift_right_padding_zeroes/imm32/subx-name
18230     3/imm32/rm32-is-first-output
18231     0/imm32/no-r32
18232     0/imm32/no-imm32
18233     1/imm32/imm8-is-first-inout
18234     0/imm32/no-disp32
18235     0/imm32/output-is-write-only
18236     0x11/imm32/alloc-id:fake
18237     _Primitive-shift-reg-right-signed-by-lit/imm32/next
18238 _Primitive-shift-reg-right-signed-by-lit:  # (payload primitive)
18239     0x11/imm32/alloc-id:fake:payload
18240     # var1/reg <- shift-right-signed lit => c1/shift 7/subop/right-preserving-sign var1/rm32 lit/imm32
18241     0x11/imm32/alloc-id:fake
18242     _string-shift-right-signed/imm32/name
18243     0x11/imm32/alloc-id:fake
18244     Single-lit-var/imm32/inouts
18245     0x11/imm32/alloc-id:fake
18246     Single-int-var-in-some-register/imm32/outputs
18247     0x11/imm32/alloc-id:fake
18248     _string_c1_subop_shift_right_preserving_sign/imm32/subx-name
18249     3/imm32/rm32-is-first-output
18250     0/imm32/no-r32
18251     0/imm32/no-imm32
18252     1/imm32/imm8-is-first-inout
18253     0/imm32/no-disp32
18254     0/imm32/output-is-write-only
18255     0x11/imm32/alloc-id:fake
18256     _Primitive-shift-mem-left-by-lit/imm32/next
18257 _Primitive-shift-mem-left-by-lit:  # (payload primitive)
18258     0x11/imm32/alloc-id:fake:payload
18259     # shift-left var1, lit => c1/shift 4/subop/left var1/rm32 lit/imm32
18260     0x11/imm32/alloc-id:fake
18261     _string-shift-left/imm32/name
18262     0x11/imm32/alloc-id:fake
18263     Int-var-and-literal/imm32/inouts
18264     0/imm32/no-outputs
18265     0/imm32/no-outputs
18266     0x11/imm32/alloc-id:fake
18267     _string_c1_subop_shift_left/imm32/subx-name
18268     1/imm32/rm32-is-first-inout
18269     0/imm32/no-r32
18270     0/imm32/no-imm32
18271     2/imm32/imm8-is-second-inout
18272     0/imm32/no-disp32
18273     0/imm32/output-is-write-only
18274     0x11/imm32/alloc-id:fake
18275     _Primitive-shift-mem-right-by-lit/imm32/next
18276 _Primitive-shift-mem-right-by-lit:  # (payload primitive)
18277     0x11/imm32/alloc-id:fake:payload
18278     # shift-right var1, lit => c1/shift 5/subop/right var1/rm32 lit/imm32
18279     0x11/imm32/alloc-id:fake
18280     _string-shift-right/imm32/name
18281     0x11/imm32/alloc-id:fake
18282     Int-var-and-literal/imm32/inouts
18283     0/imm32/no-outputs
18284     0/imm32/no-outputs
18285     0x11/imm32/alloc-id:fake
18286     _string_c1_subop_shift_right_padding_zeroes/imm32/subx-name
18287     1/imm32/rm32-is-first-inout
18288     0/imm32/no-r32
18289     0/imm32/no-imm32
18290     2/imm32/imm8-is-second-inout
18291     0/imm32/no-disp32
18292     0/imm32/output-is-write-only
18293     0x11/imm32/alloc-id:fake
18294     _Primitive-shift-mem-right-signed-by-lit/imm32/next
18295 _Primitive-shift-mem-right-signed-by-lit:  # (payload primitive)
18296     0x11/imm32/alloc-id:fake:payload
18297     # shift-right-signed var1, lit => c1/shift 7/subop/right-preserving-sign var1/rm32 lit/imm32
18298     0x11/imm32/alloc-id:fake
18299     _string-shift-right-signed/imm32/name
18300     0x11/imm32/alloc-id:fake
18301     Int-var-and-literal/imm32/inouts
18302     0/imm32/no-outputs
18303     0/imm32/no-outputs
18304     0x11/imm32/alloc-id:fake
18305     _string_c1_subop_shift_right_preserving_sign/imm32/subx-name
18306     1/imm32/rm32-is-first-inout
18307     0/imm32/no-r32
18308     0/imm32/no-imm32
18309     2/imm32/imm8-is-second-inout
18310     0/imm32/no-disp32
18311     0/imm32/output-is-write-only
18312     0x11/imm32/alloc-id:fake
18313     _Primitive-copy-to-eax/imm32/next
18314 # - copy
18315 _Primitive-copy-to-eax:  # (payload primitive)
18316     0x11/imm32/alloc-id:fake:payload
18317     # var/eax <- copy lit => b8/copy-to-eax lit/imm32
18318     0x11/imm32/alloc-id:fake
18319     _string-copy/imm32/name
18320     0x11/imm32/alloc-id:fake
18321     Single-lit-var/imm32/inouts
18322     0x11/imm32/alloc-id:fake
18323     Single-int-var-in-eax/imm32/outputs
18324     0x11/imm32/alloc-id:fake
18325     _string_b8_copy_to_eax/imm32/subx-name
18326     0/imm32/no-rm32
18327     0/imm32/no-r32
18328     1/imm32/imm32-is-first-inout
18329     0/imm32/no-imm8
18330     0/imm32/no-disp32
18331     1/imm32/output-is-write-only
18332     0x11/imm32/alloc-id:fake
18333     _Primitive-copy-to-ecx/imm32/next
18334 _Primitive-copy-to-ecx:  # (payload primitive)
18335     0x11/imm32/alloc-id:fake:payload
18336     # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32
18337     0x11/imm32/alloc-id:fake
18338     _string-copy/imm32/name
18339     0x11/imm32/alloc-id:fake
18340     Single-lit-var/imm32/inouts
18341     0x11/imm32/alloc-id:fake
18342     Single-int-var-in-ecx/imm32/outputs
18343     0x11/imm32/alloc-id:fake
18344     _string_b9_copy_to_ecx/imm32/subx-name
18345     0/imm32/no-rm32
18346     0/imm32/no-r32
18347     1/imm32/imm32-is-first-inout
18348     0/imm32/no-imm8
18349     0/imm32/no-disp32
18350     1/imm32/output-is-write-only
18351     0x11/imm32/alloc-id:fake
18352     _Primitive-copy-to-edx/imm32/next
18353 _Primitive-copy-to-edx:  # (payload primitive)
18354     0x11/imm32/alloc-id:fake:payload
18355     # var/edx <- copy lit => ba/copy-to-edx lit/imm32
18356     0x11/imm32/alloc-id:fake
18357     _string-copy/imm32/name
18358     0x11/imm32/alloc-id:fake
18359     Single-lit-var/imm32/inouts
18360     0x11/imm32/alloc-id:fake
18361     Single-int-var-in-edx/imm32/outputs
18362     0x11/imm32/alloc-id:fake
18363     _string_ba_copy_to_edx/imm32/subx-name
18364     0/imm32/no-rm32
18365     0/imm32/no-r32
18366     1/imm32/imm32-is-first-inout
18367     0/imm32/no-imm8
18368     0/imm32/no-disp32
18369     1/imm32/output-is-write-only
18370     0x11/imm32/alloc-id:fake
18371     _Primitive-copy-to-ebx/imm32/next
18372 _Primitive-copy-to-ebx:  # (payload primitive)
18373     0x11/imm32/alloc-id:fake:payload
18374     # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32
18375     0x11/imm32/alloc-id:fake
18376     _string-copy/imm32/name
18377     0x11/imm32/alloc-id:fake
18378     Single-lit-var/imm32/inouts
18379     0x11/imm32/alloc-id:fake
18380     Single-int-var-in-ebx/imm32/outputs
18381     0x11/imm32/alloc-id:fake
18382     _string_bb_copy_to_ebx/imm32/subx-name
18383     0/imm32/no-rm32
18384     0/imm32/no-r32
18385     1/imm32/imm32-is-first-inout
18386     0/imm32/no-imm8
18387     0/imm32/no-disp32
18388     1/imm32/output-is-write-only
18389     0x11/imm32/alloc-id:fake
18390     _Primitive-copy-to-esi/imm32/next
18391 _Primitive-copy-to-esi:  # (payload primitive)
18392     0x11/imm32/alloc-id:fake:payload
18393     # var/esi <- copy lit => be/copy-to-esi lit/imm32
18394     0x11/imm32/alloc-id:fake
18395     _string-copy/imm32/name
18396     0x11/imm32/alloc-id:fake
18397     Single-lit-var/imm32/inouts
18398     0x11/imm32/alloc-id:fake
18399     Single-int-var-in-esi/imm32/outputs
18400     0x11/imm32/alloc-id:fake
18401     _string_be_copy_to_esi/imm32/subx-name
18402     0/imm32/no-rm32
18403     0/imm32/no-r32
18404     1/imm32/imm32-is-first-inout
18405     0/imm32/no-imm8
18406     0/imm32/no-disp32
18407     1/imm32/output-is-write-only
18408     0x11/imm32/alloc-id:fake
18409     _Primitive-copy-to-edi/imm32/next
18410 _Primitive-copy-to-edi:  # (payload primitive)
18411     0x11/imm32/alloc-id:fake:payload
18412     # var/edi <- copy lit => bf/copy-to-edi lit/imm32
18413     0x11/imm32/alloc-id:fake
18414     _string-copy/imm32/name
18415     0x11/imm32/alloc-id:fake
18416     Single-lit-var/imm32/inouts
18417     0x11/imm32/alloc-id:fake
18418     Single-int-var-in-edi/imm32/outputs
18419     0x11/imm32/alloc-id:fake
18420     _string_bf_copy_to_edi/imm32/subx-name
18421     0/imm32/no-rm32
18422     0/imm32/no-r32
18423     1/imm32/imm32-is-first-inout
18424     0/imm32/no-imm8
18425     0/imm32/no-disp32
18426     1/imm32/output-is-write-only
18427     0x11/imm32/alloc-id:fake
18428     _Primitive-copy-reg-to-reg/imm32/next
18429 _Primitive-copy-reg-to-reg:  # (payload primitive)
18430     0x11/imm32/alloc-id:fake:payload
18431     # var1/reg <- copy var2/reg => 89/<- var1/rm32 var2/r32
18432     0x11/imm32/alloc-id:fake
18433     _string-copy/imm32/name
18434     0x11/imm32/alloc-id:fake
18435     Single-int-var-in-some-register/imm32/inouts
18436     0x11/imm32/alloc-id:fake
18437     Single-int-var-in-some-register/imm32/outputs
18438     0x11/imm32/alloc-id:fake
18439     _string_89_<-/imm32/subx-name
18440     3/imm32/rm32-is-first-output
18441     1/imm32/r32-is-first-inout
18442     0/imm32/no-imm32
18443     0/imm32/no-imm8
18444     0/imm32/no-disp32
18445     1/imm32/output-is-write-only
18446     0x11/imm32/alloc-id:fake
18447     _Primitive-copy-reg-to-mem/imm32/next
18448 _Primitive-copy-reg-to-mem:  # (payload primitive)
18449     0x11/imm32/alloc-id:fake:payload
18450     # copy-to var1 var2/reg => 89/<- var1 var2/r32
18451     0x11/imm32/alloc-id:fake
18452     _string-copy-to/imm32/name
18453     0x11/imm32/alloc-id:fake
18454     Two-args-int-stack-int-reg/imm32/inouts
18455     0/imm32/no-outputs
18456     0/imm32/no-outputs
18457     0x11/imm32/alloc-id:fake
18458     _string_89_<-/imm32/subx-name
18459     1/imm32/rm32-is-first-inout
18460     2/imm32/r32-is-second-inout
18461     0/imm32/no-imm32
18462     0/imm32/no-imm8
18463     0/imm32/no-disp32
18464     1/imm32/output-is-write-only
18465     0x11/imm32/alloc-id:fake
18466     _Primitive-copy-mem-to-reg/imm32/next
18467 _Primitive-copy-mem-to-reg:  # (payload primitive)
18468     0x11/imm32/alloc-id:fake:payload
18469     # var1/reg <- copy var2 => 8b/-> var2/rm32 var1/r32
18470     0x11/imm32/alloc-id:fake
18471     _string-copy/imm32/name
18472     0x11/imm32/alloc-id:fake
18473     Single-int-var-in-mem/imm32/inouts
18474     0x11/imm32/alloc-id:fake
18475     Single-int-var-in-some-register/imm32/outputs
18476     0x11/imm32/alloc-id:fake
18477     _string_8b_->/imm32/subx-name
18478     1/imm32/rm32-is-first-inout
18479     3/imm32/r32-is-first-output
18480     0/imm32/no-imm32
18481     0/imm32/no-imm8
18482     0/imm32/no-disp32
18483     1/imm32/output-is-write-only
18484     0x11/imm32/alloc-id:fake
18485     _Primitive-copy-lit-to-reg/imm32/next
18486 _Primitive-copy-lit-to-reg:  # (payload primitive)
18487     0x11/imm32/alloc-id:fake:payload
18488     # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32
18489     0x11/imm32/alloc-id:fake
18490     _string-copy/imm32/name
18491     0x11/imm32/alloc-id:fake
18492     Single-lit-var/imm32/inouts
18493     0x11/imm32/alloc-id:fake
18494     Single-int-var-in-some-register/imm32/outputs
18495     0x11/imm32/alloc-id:fake
18496     _string_c7_subop_copy/imm32/subx-name
18497     3/imm32/rm32-is-first-output
18498     0/imm32/no-r32
18499     1/imm32/imm32-is-first-inout
18500     0/imm32/no-imm8
18501     0/imm32/no-disp32
18502     1/imm32/output-is-write-only
18503     0x11/imm32/alloc-id:fake
18504     _Primitive-copy-lit-to-mem/imm32/next
18505 _Primitive-copy-lit-to-mem:  # (payload primitive)
18506     0x11/imm32/alloc-id:fake:payload
18507     # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32
18508     0x11/imm32/alloc-id:fake
18509     _string-copy-to/imm32/name
18510     0x11/imm32/alloc-id:fake
18511     Int-var-and-literal/imm32/inouts
18512     0/imm32/no-outputs
18513     0/imm32/no-outputs
18514     0x11/imm32/alloc-id:fake
18515     _string_c7_subop_copy/imm32/subx-name
18516     1/imm32/rm32-is-first-inout
18517     0/imm32/no-r32
18518     2/imm32/imm32-is-second-inout
18519     0/imm32/no-imm8
18520     0/imm32/no-disp32
18521     1/imm32/output-is-write-only
18522     0x11/imm32/alloc-id:fake
18523     _Primitive-copy-byte-from-reg/imm32/next
18524 # - copy byte
18525 _Primitive-copy-byte-from-reg:
18526     0x11/imm32/alloc-id:fake:payload
18527     # var/reg <- copy-byte var2/reg2 => 8a/byte-> %var2 var/r32
18528     0x11/imm32/alloc-id:fake
18529     _string-copy-byte/imm32/name
18530     0x11/imm32/alloc-id:fake
18531     Single-byte-var-in-some-register/imm32/inouts
18532     0x11/imm32/alloc-id:fake
18533     Single-byte-var-in-some-register/imm32/outputs
18534     0x11/imm32/alloc-id:fake
18535     _string_8a_copy_byte/imm32/subx-name
18536     1/imm32/rm32-is-first-inout
18537     3/imm32/r32-is-first-output
18538     0/imm32/no-imm32
18539     0/imm32/no-imm8
18540     0/imm32/no-disp32
18541     1/imm32/output-is-write-only
18542     0x11/imm32/alloc-id:fake
18543     _Primitive-copy-byte-from-mem/imm32/next
18544 _Primitive-copy-byte-from-mem:
18545     0x11/imm32/alloc-id:fake:payload
18546     # var/reg <- copy-byte *var2/reg2 => 8a/byte-> *var2 var/r32
18547     0x11/imm32/alloc-id:fake
18548     _string-copy-byte/imm32/name
18549     0x11/imm32/alloc-id:fake
18550     Single-byte-var-in-mem/imm32/inouts
18551     0x11/imm32/alloc-id:fake
18552     Single-byte-var-in-some-register/imm32/outputs
18553     0x11/imm32/alloc-id:fake
18554     _string_8a_copy_byte/imm32/subx-name
18555     1/imm32/rm32-is-first-inout
18556     3/imm32/r32-is-first-output
18557     0/imm32/no-imm32
18558     0/imm32/no-imm8
18559     0/imm32/no-disp32
18560     1/imm32/output-is-write-only
18561     0x11/imm32/alloc-id:fake
18562     _Primitive-copy-byte-to-mem/imm32/next
18563 _Primitive-copy-byte-to-mem:
18564     0x11/imm32/alloc-id:fake:payload
18565     # copy-byte-to *var1/reg1, var2/reg2 => 88/byte<- *reg1 reg2/r32
18566     0x11/imm32/alloc-id:fake
18567     _string-copy-byte-to/imm32/name
18568     0x11/imm32/alloc-id:fake
18569     Two-args-byte-stack-byte-reg/imm32/inouts
18570     0/imm32/no-outputs
18571     0/imm32/no-outputs
18572     0x11/imm32/alloc-id:fake
18573     _string_88_copy_byte/imm32/subx-name
18574     1/imm32/rm32-is-first-inout
18575     2/imm32/r32-is-second-inout
18576     0/imm32/no-imm32
18577     0/imm32/no-imm8
18578     0/imm32/no-disp32
18579     0/imm32/output-is-write-only
18580     0x11/imm32/alloc-id:fake
18581     _Primitive-address/imm32/next
18582 # - address
18583 _Primitive-address:  # (payload primitive)
18584     0x11/imm32/alloc-id:fake:payload
18585     # var1/reg <- address var2 => 8d/copy-address var2/rm32 var1/r32
18586     0x11/imm32/alloc-id:fake
18587     _string-address/imm32/name
18588     0x11/imm32/alloc-id:fake
18589     Single-int-var-in-mem/imm32/inouts
18590     0x11/imm32/alloc-id:fake
18591     Single-addr-var-in-some-register/imm32/outputs
18592     0x11/imm32/alloc-id:fake
18593     _string_8d_copy_address/imm32/subx-name
18594     1/imm32/rm32-is-first-inout
18595     3/imm32/r32-is-first-output
18596     0/imm32/no-imm32
18597     0/imm32/no-imm8
18598     0/imm32/no-disp32
18599     1/imm32/output-is-write-only
18600     0x11/imm32/alloc-id:fake
18601     _Primitive-compare-reg-with-reg/imm32/next
18602 # - compare
18603 _Primitive-compare-reg-with-reg:  # (payload primitive)
18604     0x11/imm32/alloc-id:fake:payload
18605     # compare var1/reg1 var2/reg2 => 39/compare var1/rm32 var2/r32
18606     0x11/imm32/alloc-id:fake
18607     _string-compare/imm32/name
18608     0x11/imm32/alloc-id:fake
18609     Two-int-args-in-regs/imm32/inouts
18610     0/imm32/no-outputs
18611     0/imm32/no-outputs
18612     0x11/imm32/alloc-id:fake
18613     _string_39_compare->/imm32/subx-name
18614     1/imm32/rm32-is-first-inout
18615     2/imm32/r32-is-second-inout
18616     0/imm32/no-imm32
18617     0/imm32/no-imm8
18618     0/imm32/no-disp32
18619     0/imm32/output-is-write-only
18620     0x11/imm32/alloc-id:fake
18621     _Primitive-compare-mem-with-reg/imm32/next
18622 _Primitive-compare-mem-with-reg:  # (payload primitive)
18623     0x11/imm32/alloc-id:fake:payload
18624     # compare var1 var2/reg => 39/compare var1/rm32 var2/r32
18625     0x11/imm32/alloc-id:fake
18626     _string-compare/imm32/name
18627     0x11/imm32/alloc-id:fake
18628     Two-args-int-stack-int-reg/imm32/inouts
18629     0/imm32/no-outputs
18630     0/imm32/no-outputs
18631     0x11/imm32/alloc-id:fake
18632     _string_39_compare->/imm32/subx-name
18633     1/imm32/rm32-is-first-inout
18634     2/imm32/r32-is-second-inout
18635     0/imm32/no-imm32
18636     0/imm32/no-imm8
18637     0/imm32/no-disp32
18638     0/imm32/output-is-write-only
18639     0x11/imm32/alloc-id:fake
18640     _Primitive-compare-reg-with-mem/imm32/next
18641 _Primitive-compare-reg-with-mem:  # (payload primitive)
18642     0x11/imm32/alloc-id:fake:payload
18643     # compare var1/reg var2 => 3b/compare<- var2/rm32 var1/r32
18644     0x11/imm32/alloc-id:fake
18645     _string-compare/imm32/name
18646     0x11/imm32/alloc-id:fake
18647     Two-args-int-reg-int-stack/imm32/inouts
18648     0/imm32/no-outputs
18649     0/imm32/no-outputs
18650     0x11/imm32/alloc-id:fake
18651     _string_3b_compare<-/imm32/subx-name
18652     2/imm32/rm32-is-second-inout
18653     1/imm32/r32-is-first-inout
18654     0/imm32/no-imm32
18655     0/imm32/no-imm8
18656     0/imm32/no-disp32
18657     0/imm32/output-is-write-only
18658     0x11/imm32/alloc-id:fake
18659     _Primitive-compare-eax-with-literal/imm32/next
18660 _Primitive-compare-eax-with-literal:  # (payload primitive)
18661     0x11/imm32/alloc-id:fake:payload
18662     # compare var1/eax n => 3d/compare-eax-with n/imm32
18663     0x11/imm32/alloc-id:fake
18664     _string-compare/imm32/name
18665     0x11/imm32/alloc-id:fake
18666     Two-args-int-eax-int-literal/imm32/inouts
18667     0/imm32/no-outputs
18668     0/imm32/no-outputs
18669     0x11/imm32/alloc-id:fake
18670     _string_3d_compare_eax_with/imm32/subx-name
18671     0/imm32/no-rm32
18672     0/imm32/no-r32
18673     2/imm32/imm32-is-second-inout
18674     0/imm32/no-imm8
18675     0/imm32/no-disp32
18676     0/imm32/output-is-write-only
18677     0x11/imm32/alloc-id:fake
18678     _Primitive-compare-reg-with-literal/imm32/next
18679 _Primitive-compare-reg-with-literal:  # (payload primitive)
18680     0x11/imm32/alloc-id:fake:payload
18681     # compare var1/reg n => 81 7/subop/compare %reg n/imm32
18682     0x11/imm32/alloc-id:fake
18683     _string-compare/imm32/name
18684     0x11/imm32/alloc-id:fake
18685     Int-var-in-register-and-literal/imm32/inouts
18686     0/imm32/no-outputs
18687     0/imm32/no-outputs
18688     0x11/imm32/alloc-id:fake
18689     _string_81_subop_compare/imm32/subx-name
18690     1/imm32/rm32-is-first-inout
18691     0/imm32/no-r32
18692     2/imm32/imm32-is-second-inout
18693     0/imm32/no-imm8
18694     0/imm32/no-disp32
18695     0/imm32/output-is-write-only
18696     0x11/imm32/alloc-id:fake
18697     _Primitive-compare-mem-with-literal/imm32/next
18698 _Primitive-compare-mem-with-literal:  # (payload primitive)
18699     0x11/imm32/alloc-id:fake:payload
18700     # compare var1 n => 81 7/subop/compare *(ebp+___) n/imm32
18701     0x11/imm32/alloc-id:fake
18702     _string-compare/imm32/name
18703     0x11/imm32/alloc-id:fake
18704     Int-var-and-literal/imm32/inouts
18705     0/imm32/no-outputs
18706     0/imm32/no-outputs
18707     0x11/imm32/alloc-id:fake
18708     _string_81_subop_compare/imm32/subx-name
18709     1/imm32/rm32-is-first-inout
18710     0/imm32/no-r32
18711     2/imm32/imm32-is-second-inout
18712     0/imm32/no-imm8
18713     0/imm32/no-disp32
18714     0/imm32/output-is-write-only
18715     0x11/imm32/alloc-id:fake
18716     _Primitive-multiply-reg-by-reg/imm32/next
18717 # - multiply
18718 _Primitive-multiply-reg-by-reg:  # (payload primitive)
18719     0x11/imm32/alloc-id:fake:payload
18720     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
18721     0x11/imm32/alloc-id:fake
18722     _string-multiply/imm32/name
18723     0x11/imm32/alloc-id:fake
18724     Single-int-var-in-some-register/imm32/inouts
18725     0x11/imm32/alloc-id:fake
18726     Single-int-var-in-some-register/imm32/outputs
18727     0x11/imm32/alloc-id:fake
18728     _string_0f_af_multiply/imm32/subx-name
18729     1/imm32/rm32-is-first-inout
18730     3/imm32/r32-is-first-output
18731     0/imm32/no-imm32
18732     0/imm32/no-imm8
18733     0/imm32/no-disp32
18734     0/imm32/output-is-write-only
18735     0x11/imm32/alloc-id:fake
18736     _Primitive-multiply-reg-by-mem/imm32/next
18737 _Primitive-multiply-reg-by-mem:  # (payload primitive)
18738     0x11/imm32/alloc-id:fake:payload
18739     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
18740     0x11/imm32/alloc-id:fake
18741     _string-multiply/imm32/name
18742     0x11/imm32/alloc-id:fake
18743     Single-int-var-in-mem/imm32/inouts
18744     0x11/imm32/alloc-id:fake
18745     Single-int-var-in-some-register/imm32/outputs
18746     0x11/imm32/alloc-id:fake
18747     _string_0f_af_multiply/imm32/subx-name
18748     1/imm32/rm32-is-first-inout
18749     3/imm32/r32-is-first-output
18750     0/imm32/no-imm32
18751     0/imm32/no-imm8
18752     0/imm32/no-disp32
18753     0/imm32/output-is-write-only
18754     0x11/imm32/alloc-id:fake
18755     _Primitive-break-if-addr</imm32/next
18756 # - branches
18757 _Primitive-break-if-addr<:  # (payload primitive)
18758     0x11/imm32/alloc-id:fake:payload
18759     0x11/imm32/alloc-id:fake
18760     _string-break-if-addr</imm32/name
18761     0/imm32/no-inouts
18762     0/imm32/no-inouts
18763     0/imm32/no-outputs
18764     0/imm32/no-outputs
18765     0x11/imm32/alloc-id:fake
18766     _string_0f_82_jump_break/imm32/subx-name
18767     0/imm32/no-rm32
18768     0/imm32/no-r32
18769     0/imm32/no-imm32
18770     0/imm32/no-imm8
18771     0/imm32/no-disp32
18772     0/imm32/no-output
18773     0x11/imm32/alloc-id:fake
18774     _Primitive-break-if-addr>=/imm32/next
18775 _Primitive-break-if-addr>=:  # (payload primitive)
18776     0x11/imm32/alloc-id:fake:payload
18777     0x11/imm32/alloc-id:fake
18778     _string-break-if-addr>=/imm32/name
18779     0/imm32/no-inouts
18780     0/imm32/no-inouts
18781     0/imm32/no-outputs
18782     0/imm32/no-outputs
18783     0x11/imm32/alloc-id:fake
18784     _string_0f_83_jump_break/imm32/subx-name
18785     0/imm32/no-rm32
18786     0/imm32/no-r32
18787     0/imm32/no-imm32
18788     0/imm32/no-imm8
18789     0/imm32/no-disp32
18790     0/imm32/no-output
18791     0x11/imm32/alloc-id:fake
18792     _Primitive-break-if-=/imm32/next
18793 _Primitive-break-if-=:  # (payload primitive)
18794     0x11/imm32/alloc-id:fake:payload
18795     0x11/imm32/alloc-id:fake
18796     _string-break-if-=/imm32/name
18797     0/imm32/no-inouts
18798     0/imm32/no-inouts
18799     0/imm32/no-outputs
18800     0/imm32/no-outputs
18801     0x11/imm32/alloc-id:fake
18802     _string_0f_84_jump_break/imm32/subx-name
18803     0/imm32/no-rm32
18804     0/imm32/no-r32
18805     0/imm32/no-imm32
18806     0/imm32/no-imm8
18807     0/imm32/no-disp32
18808     0/imm32/no-output
18809     0x11/imm32/alloc-id:fake
18810     _Primitive-break-if-!=/imm32/next
18811 _Primitive-break-if-!=:  # (payload primitive)
18812     0x11/imm32/alloc-id:fake:payload
18813     0x11/imm32/alloc-id:fake
18814     _string-break-if-!=/imm32/name
18815     0/imm32/no-inouts
18816     0/imm32/no-inouts
18817     0/imm32/no-outputs
18818     0/imm32/no-outputs
18819     0x11/imm32/alloc-id:fake
18820     _string_0f_85_jump_break/imm32/subx-name
18821     0/imm32/no-rm32
18822     0/imm32/no-r32
18823     0/imm32/no-imm32
18824     0/imm32/no-imm8
18825     0/imm32/no-disp32
18826     0/imm32/no-output
18827     0x11/imm32/alloc-id:fake
18828     _Primitive-break-if-addr<=/imm32/next
18829 _Primitive-break-if-addr<=:  # (payload primitive)
18830     0x11/imm32/alloc-id:fake:payload
18831     0x11/imm32/alloc-id:fake
18832     _string-break-if-addr<=/imm32/name
18833     0/imm32/no-inouts
18834     0/imm32/no-inouts
18835     0/imm32/no-outputs
18836     0/imm32/no-outputs
18837     0x11/imm32/alloc-id:fake
18838     _string_0f_86_jump_break/imm32/subx-name
18839     0/imm32/no-rm32
18840     0/imm32/no-r32
18841     0/imm32/no-imm32
18842     0/imm32/no-imm8
18843     0/imm32/no-disp32
18844     0/imm32/no-output
18845     0x11/imm32/alloc-id:fake
18846     _Primitive-break-if-addr>/imm32/next
18847 _Primitive-break-if-addr>:  # (payload primitive)
18848     0x11/imm32/alloc-id:fake:payload
18849     0x11/imm32/alloc-id:fake
18850     _string-break-if-addr>/imm32/name
18851     0/imm32/no-inouts
18852     0/imm32/no-inouts
18853     0/imm32/no-outputs
18854     0/imm32/no-outputs
18855     0x11/imm32/alloc-id:fake
18856     _string_0f_87_jump_break/imm32/subx-name
18857     0/imm32/no-rm32
18858     0/imm32/no-r32
18859     0/imm32/no-imm32
18860     0/imm32/no-imm8
18861     0/imm32/no-disp32
18862     0/imm32/no-output
18863     0x11/imm32/alloc-id:fake
18864     _Primitive-break-if-</imm32/next
18865 _Primitive-break-if-<:  # (payload primitive)
18866     0x11/imm32/alloc-id:fake:payload
18867     0x11/imm32/alloc-id:fake
18868     _string-break-if-</imm32/name
18869     0/imm32/no-inouts
18870     0/imm32/no-inouts
18871     0/imm32/no-outputs
18872     0/imm32/no-outputs
18873     0x11/imm32/alloc-id:fake
18874     _string_0f_8c_jump_break/imm32/subx-name
18875     0/imm32/no-rm32
18876     0/imm32/no-r32
18877     0/imm32/no-imm32
18878     0/imm32/no-imm8
18879     0/imm32/no-disp32
18880     0/imm32/no-output
18881     0x11/imm32/alloc-id:fake
18882     _Primitive-break-if->=/imm32/next
18883 _Primitive-break-if->=:  # (payload primitive)
18884     0x11/imm32/alloc-id:fake:payload
18885     0x11/imm32/alloc-id:fake
18886     _string-break-if->=/imm32/name
18887     0/imm32/no-inouts
18888     0/imm32/no-inouts
18889     0/imm32/no-outputs
18890     0/imm32/no-outputs
18891     0x11/imm32/alloc-id:fake
18892     _string_0f_8d_jump_break/imm32/subx-name
18893     0/imm32/no-rm32
18894     0/imm32/no-r32
18895     0/imm32/no-imm32
18896     0/imm32/no-imm8
18897     0/imm32/no-disp32
18898     0/imm32/no-output
18899     0x11/imm32/alloc-id:fake
18900     _Primitive-break-if-<=/imm32/next
18901 _Primitive-break-if-<=:  # (payload primitive)
18902     0x11/imm32/alloc-id:fake:payload
18903     0x11/imm32/alloc-id:fake
18904     _string-break-if-<=/imm32/name
18905     0/imm32/no-inouts
18906     0/imm32/no-inouts
18907     0/imm32/no-outputs
18908     0/imm32/no-outputs
18909     0x11/imm32/alloc-id:fake
18910     _string_0f_8e_jump_break/imm32/subx-name
18911     0/imm32/no-rm32
18912     0/imm32/no-r32
18913     0/imm32/no-imm32
18914     0/imm32/no-imm8
18915     0/imm32/no-disp32
18916     0/imm32/no-output
18917     0x11/imm32/alloc-id:fake
18918     _Primitive-break-if->/imm32/next
18919 _Primitive-break-if->:  # (payload primitive)
18920     0x11/imm32/alloc-id:fake:payload
18921     0x11/imm32/alloc-id:fake
18922     _string-break-if->/imm32/name
18923     0/imm32/no-inouts
18924     0/imm32/no-inouts
18925     0/imm32/no-outputs
18926     0/imm32/no-outputs
18927     0x11/imm32/alloc-id:fake
18928     _string_0f_8f_jump_break/imm32/subx-name
18929     0/imm32/no-rm32
18930     0/imm32/no-r32
18931     0/imm32/no-imm32
18932     0/imm32/no-imm8
18933     0/imm32/no-disp32
18934     0/imm32/no-output
18935     0x11/imm32/alloc-id:fake
18936     _Primitive-break/imm32/next
18937 _Primitive-break:  # (payload primitive)
18938     0x11/imm32/alloc-id:fake:payload
18939     0x11/imm32/alloc-id:fake
18940     _string-break/imm32/name
18941     0/imm32/no-inouts
18942     0/imm32/no-inouts
18943     0/imm32/no-outputs
18944     0/imm32/no-outputs
18945     0x11/imm32/alloc-id:fake
18946     _string_e9_jump_break/imm32/subx-name
18947     0/imm32/no-rm32
18948     0/imm32/no-r32
18949     0/imm32/no-imm32
18950     0/imm32/no-imm8
18951     0/imm32/no-disp32
18952     0/imm32/no-output
18953     0x11/imm32/alloc-id:fake
18954     _Primitive-loop-if-addr</imm32/next
18955 _Primitive-loop-if-addr<:  # (payload primitive)
18956     0x11/imm32/alloc-id:fake:payload
18957     0x11/imm32/alloc-id:fake
18958     _string-loop-if-addr</imm32/name
18959     0/imm32/no-inouts
18960     0/imm32/no-inouts
18961     0/imm32/no-outputs
18962     0/imm32/no-outputs
18963     0x11/imm32/alloc-id:fake
18964     _string_0f_82_jump_loop/imm32/subx-name
18965     0/imm32/no-rm32
18966     0/imm32/no-r32
18967     0/imm32/no-imm32
18968     0/imm32/no-imm8
18969     0/imm32/no-disp32
18970     0/imm32/no-output
18971     0x11/imm32/alloc-id:fake
18972     _Primitive-loop-if-addr>=/imm32/next
18973 _Primitive-loop-if-addr>=:  # (payload primitive)
18974     0x11/imm32/alloc-id:fake:payload
18975     0x11/imm32/alloc-id:fake
18976     _string-loop-if-addr>=/imm32/name
18977     0/imm32/no-inouts
18978     0/imm32/no-inouts
18979     0/imm32/no-outputs
18980     0/imm32/no-outputs
18981     0x11/imm32/alloc-id:fake
18982     _string_0f_83_jump_loop/imm32/subx-name
18983     0/imm32/no-rm32
18984     0/imm32/no-r32
18985     0/imm32/no-imm32
18986     0/imm32/no-imm8
18987     0/imm32/no-disp32
18988     0/imm32/no-output
18989     0x11/imm32/alloc-id:fake
18990     _Primitive-loop-if-=/imm32/next
18991 _Primitive-loop-if-=:  # (payload primitive)
18992     0x11/imm32/alloc-id:fake:payload
18993     0x11/imm32/alloc-id:fake
18994     _string-loop-if-=/imm32/name
18995     0/imm32/no-inouts
18996     0/imm32/no-inouts
18997     0/imm32/no-outputs
18998     0/imm32/no-outputs
18999     0x11/imm32/alloc-id:fake
19000     _string_0f_84_jump_loop/imm32/subx-name
19001     0/imm32/no-rm32
19002     0/imm32/no-r32
19003     0/imm32/no-imm32
19004     0/imm32/no-imm8
19005     0/imm32/no-disp32
19006     0/imm32/no-output
19007     0x11/imm32/alloc-id:fake
19008     _Primitive-loop-if-!=/imm32/next
19009 _Primitive-loop-if-!=:  # (payload primitive)
19010     0x11/imm32/alloc-id:fake:payload
19011     0x11/imm32/alloc-id:fake
19012     _string-loop-if-!=/imm32/name
19013     0/imm32/no-inouts
19014     0/imm32/no-inouts
19015     0/imm32/no-outputs
19016     0/imm32/no-outputs
19017     0x11/imm32/alloc-id:fake
19018     _string_0f_85_jump_loop/imm32/subx-name
19019     0/imm32/no-rm32
19020     0/imm32/no-r32
19021     0/imm32/no-imm32
19022     0/imm32/no-imm8
19023     0/imm32/no-disp32
19024     0/imm32/no-output
19025     0x11/imm32/alloc-id:fake
19026     _Primitive-loop-if-addr<=/imm32/next
19027 _Primitive-loop-if-addr<=:  # (payload primitive)
19028     0x11/imm32/alloc-id:fake:payload
19029     0x11/imm32/alloc-id:fake
19030     _string-loop-if-addr<=/imm32/name
19031     0/imm32/no-inouts
19032     0/imm32/no-inouts
19033     0/imm32/no-outputs
19034     0/imm32/no-outputs
19035     0x11/imm32/alloc-id:fake
19036     _string_0f_86_jump_loop/imm32/subx-name
19037     0/imm32/no-rm32
19038     0/imm32/no-r32
19039     0/imm32/no-imm32
19040     0/imm32/no-imm8
19041     0/imm32/no-disp32
19042     0/imm32/no-output
19043     0x11/imm32/alloc-id:fake
19044     _Primitive-loop-if-addr>/imm32/next
19045 _Primitive-loop-if-addr>:  # (payload primitive)
19046     0x11/imm32/alloc-id:fake:payload
19047     0x11/imm32/alloc-id:fake
19048     _string-loop-if-addr>/imm32/name
19049     0/imm32/no-inouts
19050     0/imm32/no-inouts
19051     0/imm32/no-outputs
19052     0/imm32/no-outputs
19053     0x11/imm32/alloc-id:fake
19054     _string_0f_87_jump_loop/imm32/subx-name
19055     0/imm32/no-rm32
19056     0/imm32/no-r32
19057     0/imm32/no-imm32
19058     0/imm32/no-imm8
19059     0/imm32/no-disp32
19060     0/imm32/no-output
19061     0x11/imm32/alloc-id:fake
19062     _Primitive-loop-if-</imm32/next
19063 _Primitive-loop-if-<:  # (payload primitive)
19064     0x11/imm32/alloc-id:fake:payload
19065     0x11/imm32/alloc-id:fake
19066     _string-loop-if-</imm32/name
19067     0/imm32/no-inouts
19068     0/imm32/no-inouts
19069     0/imm32/no-outputs
19070     0/imm32/no-outputs
19071     0x11/imm32/alloc-id:fake
19072     _string_0f_8c_jump_loop/imm32/subx-name
19073     0/imm32/no-rm32
19074     0/imm32/no-r32
19075     0/imm32/no-imm32
19076     0/imm32/no-imm8
19077     0/imm32/no-disp32
19078     0/imm32/no-output
19079     0x11/imm32/alloc-id:fake
19080     _Primitive-loop-if->=/imm32/next
19081 _Primitive-loop-if->=:  # (payload primitive)
19082     0x11/imm32/alloc-id:fake:payload
19083     0x11/imm32/alloc-id:fake
19084     _string-loop-if->=/imm32/name
19085     0/imm32/no-inouts
19086     0/imm32/no-inouts
19087     0/imm32/no-outputs
19088     0/imm32/no-outputs
19089     0x11/imm32/alloc-id:fake
19090     _string_0f_8d_jump_loop/imm32/subx-name
19091     0/imm32/no-rm32
19092     0/imm32/no-r32
19093     0/imm32/no-imm32
19094     0/imm32/no-imm8
19095     0/imm32/no-disp32
19096     0/imm32/no-output
19097     0x11/imm32/alloc-id:fake
19098     _Primitive-loop-if-<=/imm32/next
19099 _Primitive-loop-if-<=:  # (payload primitive)
19100     0x11/imm32/alloc-id:fake:payload
19101     0x11/imm32/alloc-id:fake
19102     _string-loop-if-<=/imm32/name
19103     0/imm32/no-inouts
19104     0/imm32/no-inouts
19105     0/imm32/no-outputs
19106     0/imm32/no-outputs
19107     0x11/imm32/alloc-id:fake
19108     _string_0f_8e_jump_loop/imm32/subx-name
19109     0/imm32/no-rm32
19110     0/imm32/no-r32
19111     0/imm32/no-imm32
19112     0/imm32/no-imm8
19113     0/imm32/no-disp32
19114     0/imm32/no-output
19115     0x11/imm32/alloc-id:fake
19116     _Primitive-loop-if->/imm32/next
19117 _Primitive-loop-if->:  # (payload primitive)
19118     0x11/imm32/alloc-id:fake:payload
19119     0x11/imm32/alloc-id:fake
19120     _string-loop-if->/imm32/name
19121     0/imm32/no-inouts
19122     0/imm32/no-inouts
19123     0/imm32/no-outputs
19124     0/imm32/no-outputs
19125     0x11/imm32/alloc-id:fake
19126     _string_0f_8f_jump_loop/imm32/subx-name
19127     0/imm32/no-rm32
19128     0/imm32/no-r32
19129     0/imm32/no-imm32
19130     0/imm32/no-imm8
19131     0/imm32/no-disp32
19132     0/imm32/no-output
19133     0x11/imm32/alloc-id:fake
19134     _Primitive-loop/imm32/next  # we probably don't need an unconditional break
19135 _Primitive-loop:  # (payload primitive)
19136     0x11/imm32/alloc-id:fake:payload
19137     0x11/imm32/alloc-id:fake
19138     _string-loop/imm32/name
19139     0/imm32/no-inouts
19140     0/imm32/no-inouts
19141     0/imm32/no-outputs
19142     0/imm32/no-outputs
19143     0x11/imm32/alloc-id:fake
19144     _string_e9_jump_loop/imm32/subx-name
19145     0/imm32/no-rm32
19146     0/imm32/no-r32
19147     0/imm32/no-imm32
19148     0/imm32/no-imm8
19149     0/imm32/no-disp32
19150     0/imm32/no-output
19151     0x11/imm32/alloc-id:fake
19152     _Primitive-break-if-addr<-named/imm32/next
19153 # - branches to named blocks
19154 _Primitive-break-if-addr<-named:  # (payload primitive)
19155     0x11/imm32/alloc-id:fake:payload
19156     0x11/imm32/alloc-id:fake
19157     _string-break-if-addr</imm32/name
19158     0x11/imm32/alloc-id:fake
19159     Single-lit-var/imm32/inouts
19160     0/imm32/no-outputs
19161     0/imm32/no-outputs
19162     0x11/imm32/alloc-id:fake
19163     _string_0f_82_jump_label/imm32/subx-name
19164     0/imm32/no-rm32
19165     0/imm32/no-r32
19166     0/imm32/no-imm32
19167     0/imm32/no-imm8
19168     1/imm32/disp32-is-first-inout
19169     0/imm32/no-output
19170     0x11/imm32/alloc-id:fake
19171     _Primitive-break-if-addr>=-named/imm32/next
19172 _Primitive-break-if-addr>=-named:  # (payload primitive)
19173     0x11/imm32/alloc-id:fake:payload
19174     0x11/imm32/alloc-id:fake
19175     _string-break-if-addr>=/imm32/name
19176     0x11/imm32/alloc-id:fake
19177     Single-lit-var/imm32/inouts
19178     0/imm32/no-outputs
19179     0/imm32/no-outputs
19180     0x11/imm32/alloc-id:fake
19181     _string_0f_83_jump_label/imm32/subx-name
19182     0/imm32/no-rm32
19183     0/imm32/no-r32
19184     0/imm32/no-imm32
19185     0/imm32/no-imm8
19186     1/imm32/disp32-is-first-inout
19187     0/imm32/no-output
19188     0x11/imm32/alloc-id:fake
19189     _Primitive-break-if-=-named/imm32/next
19190 _Primitive-break-if-=-named:  # (payload primitive)
19191     0x11/imm32/alloc-id:fake:payload
19192     0x11/imm32/alloc-id:fake
19193     _string-break-if-=/imm32/name
19194     0x11/imm32/alloc-id:fake
19195     Single-lit-var/imm32/inouts
19196     0/imm32/no-outputs
19197     0/imm32/no-outputs
19198     0x11/imm32/alloc-id:fake
19199     _string_0f_84_jump_label/imm32/subx-name
19200     0/imm32/no-rm32
19201     0/imm32/no-r32
19202     0/imm32/no-imm32
19203     0/imm32/no-imm8
19204     1/imm32/disp32-is-first-inout
19205     0/imm32/no-output
19206     0x11/imm32/alloc-id:fake
19207     _Primitive-break-if-!=-named/imm32/next
19208 _Primitive-break-if-!=-named:  # (payload primitive)
19209     0x11/imm32/alloc-id:fake:payload
19210     0x11/imm32/alloc-id:fake
19211     _string-break-if-!=/imm32/name
19212     0x11/imm32/alloc-id:fake
19213     Single-lit-var/imm32/inouts
19214     0/imm32/no-outputs
19215     0/imm32/no-outputs
19216     0x11/imm32/alloc-id:fake
19217     _string_0f_85_jump_label/imm32/subx-name
19218     0/imm32/no-rm32
19219     0/imm32/no-r32
19220     0/imm32/no-imm32
19221     0/imm32/no-imm8
19222     1/imm32/disp32-is-first-inout
19223     0/imm32/no-output
19224     0x11/imm32/alloc-id:fake
19225     _Primitive-break-if-addr<=-named/imm32/next
19226 _Primitive-break-if-addr<=-named:  # (payload primitive)
19227     0x11/imm32/alloc-id:fake:payload
19228     0x11/imm32/alloc-id:fake
19229     _string-break-if-addr<=/imm32/name
19230     0x11/imm32/alloc-id:fake
19231     Single-lit-var/imm32/inouts
19232     0/imm32/no-outputs
19233     0/imm32/no-outputs
19234     0x11/imm32/alloc-id:fake
19235     _string_0f_86_jump_label/imm32/subx-name
19236     0/imm32/no-rm32
19237     0/imm32/no-r32
19238     0/imm32/no-imm32
19239     0/imm32/no-imm8
19240     1/imm32/disp32-is-first-inout
19241     0/imm32/no-output
19242     0x11/imm32/alloc-id:fake
19243     _Primitive-break-if-addr>-named/imm32/next
19244 _Primitive-break-if-addr>-named:  # (payload primitive)
19245     0x11/imm32/alloc-id:fake:payload
19246     0x11/imm32/alloc-id:fake
19247     _string-break-if-addr>/imm32/name
19248     0x11/imm32/alloc-id:fake
19249     Single-lit-var/imm32/inouts
19250     0/imm32/no-outputs
19251     0/imm32/no-outputs
19252     0x11/imm32/alloc-id:fake
19253     _string_0f_87_jump_label/imm32/subx-name
19254     0/imm32/no-rm32
19255     0/imm32/no-r32
19256     0/imm32/no-imm32
19257     0/imm32/no-imm8
19258     1/imm32/disp32-is-first-inout
19259     0/imm32/no-output
19260     0x11/imm32/alloc-id:fake
19261     _Primitive-break-if-<-named/imm32/next
19262 _Primitive-break-if-<-named:  # (payload primitive)
19263     0x11/imm32/alloc-id:fake:payload
19264     0x11/imm32/alloc-id:fake
19265     _string-break-if-</imm32/name
19266     0x11/imm32/alloc-id:fake
19267     Single-lit-var/imm32/inouts
19268     0/imm32/no-outputs
19269     0/imm32/no-outputs
19270     0x11/imm32/alloc-id:fake
19271     _string_0f_8c_jump_label/imm32/subx-name
19272     0/imm32/no-rm32
19273     0/imm32/no-r32
19274     0/imm32/no-imm32
19275     0/imm32/no-imm8
19276     1/imm32/disp32-is-first-inout
19277     0/imm32/no-output
19278     0x11/imm32/alloc-id:fake
19279     _Primitive-break-if->=-named/imm32/next
19280 _Primitive-break-if->=-named:  # (payload primitive)
19281     0x11/imm32/alloc-id:fake:payload
19282     0x11/imm32/alloc-id:fake
19283     _string-break-if->=/imm32/name
19284     0x11/imm32/alloc-id:fake
19285     Single-lit-var/imm32/inouts
19286     0/imm32/no-outputs
19287     0/imm32/no-outputs
19288     0x11/imm32/alloc-id:fake
19289     _string_0f_8d_jump_label/imm32/subx-name
19290     0/imm32/no-rm32
19291     0/imm32/no-r32
19292     0/imm32/no-imm32
19293     0/imm32/no-imm8
19294     1/imm32/disp32-is-first-inout
19295     0/imm32/no-output
19296     0x11/imm32/alloc-id:fake
19297     _Primitive-break-if-<=-named/imm32/next
19298 _Primitive-break-if-<=-named:  # (payload primitive)
19299     0x11/imm32/alloc-id:fake:payload
19300     0x11/imm32/alloc-id:fake
19301     _string-break-if-<=/imm32/name
19302     0x11/imm32/alloc-id:fake
19303     Single-lit-var/imm32/inouts
19304     0/imm32/no-outputs
19305     0/imm32/no-outputs
19306     0x11/imm32/alloc-id:fake
19307     _string_0f_8e_jump_label/imm32/subx-name
19308     0/imm32/no-rm32
19309     0/imm32/no-r32
19310     0/imm32/no-imm32
19311     0/imm32/no-imm8
19312     1/imm32/disp32-is-first-inout
19313     0/imm32/no-output
19314     0x11/imm32/alloc-id:fake
19315     _Primitive-break-if->-named/imm32/next
19316 _Primitive-break-if->-named:  # (payload primitive)
19317     0x11/imm32/alloc-id:fake:payload
19318     0x11/imm32/alloc-id:fake
19319     _string-break-if->/imm32/name
19320     0x11/imm32/alloc-id:fake
19321     Single-lit-var/imm32/inouts
19322     0/imm32/no-outputs
19323     0/imm32/no-outputs
19324     0x11/imm32/alloc-id:fake
19325     _string_0f_8f_jump_label/imm32/subx-name
19326     0/imm32/no-rm32
19327     0/imm32/no-r32
19328     0/imm32/no-imm32
19329     0/imm32/no-imm8
19330     1/imm32/disp32-is-first-inout
19331     0/imm32/no-output
19332     0x11/imm32/alloc-id:fake
19333     _Primitive-break-named/imm32/next
19334 _Primitive-break-named:  # (payload primitive)
19335     0x11/imm32/alloc-id:fake:payload
19336     0x11/imm32/alloc-id:fake
19337     _string-break/imm32/name
19338     0x11/imm32/alloc-id:fake
19339     Single-lit-var/imm32/inouts
19340     0/imm32/no-outputs
19341     0/imm32/no-outputs
19342     0x11/imm32/alloc-id:fake
19343     _string_e9_jump_label/imm32/subx-name
19344     0/imm32/no-rm32
19345     0/imm32/no-r32
19346     0/imm32/no-imm32
19347     0/imm32/no-imm8
19348     1/imm32/disp32-is-first-inout
19349     0/imm32/no-output
19350     0x11/imm32/alloc-id:fake
19351     _Primitive-loop-if-addr<-named/imm32/next
19352 _Primitive-loop-if-addr<-named:  # (payload primitive)
19353     0x11/imm32/alloc-id:fake:payload
19354     0x11/imm32/alloc-id:fake
19355     _string-loop-if-addr</imm32/name
19356     0x11/imm32/alloc-id:fake
19357     Single-lit-var/imm32/inouts
19358     0/imm32/no-outputs
19359     0/imm32/no-outputs
19360     0x11/imm32/alloc-id:fake
19361     _string_0f_82_jump_label/imm32/subx-name
19362     0/imm32/no-rm32
19363     0/imm32/no-r32
19364     0/imm32/no-imm32
19365     0/imm32/no-imm8
19366     1/imm32/disp32-is-first-inout
19367     0/imm32/no-output
19368     0x11/imm32/alloc-id:fake
19369     _Primitive-loop-if-addr>=-named/imm32/next
19370 _Primitive-loop-if-addr>=-named:  # (payload primitive)
19371     0x11/imm32/alloc-id:fake:payload
19372     0x11/imm32/alloc-id:fake
19373     _string-loop-if-addr>=/imm32/name
19374     0x11/imm32/alloc-id:fake
19375     Single-lit-var/imm32/inouts
19376     0/imm32/no-outputs
19377     0/imm32/no-outputs
19378     0x11/imm32/alloc-id:fake
19379     _string_0f_83_jump_label/imm32/subx-name
19380     0/imm32/no-rm32
19381     0/imm32/no-r32
19382     0/imm32/no-imm32
19383     0/imm32/no-imm8
19384     1/imm32/disp32-is-first-inout
19385     0/imm32/no-output
19386     0x11/imm32/alloc-id:fake
19387     _Primitive-loop-if-=-named/imm32/next
19388 _Primitive-loop-if-=-named:  # (payload primitive)
19389     0x11/imm32/alloc-id:fake:payload
19390     0x11/imm32/alloc-id:fake
19391     _string-loop-if-=/imm32/name
19392     0x11/imm32/alloc-id:fake
19393     Single-lit-var/imm32/inouts
19394     0/imm32/no-outputs
19395     0/imm32/no-outputs
19396     0x11/imm32/alloc-id:fake
19397     _string_0f_84_jump_label/imm32/subx-name
19398     0/imm32/no-rm32
19399     0/imm32/no-r32
19400     0/imm32/no-imm32
19401     0/imm32/no-imm8
19402     1/imm32/disp32-is-first-inout
19403     0/imm32/no-output
19404     0x11/imm32/alloc-id:fake
19405     _Primitive-loop-if-!=-named/imm32/next
19406 _Primitive-loop-if-!=-named:  # (payload primitive)
19407     0x11/imm32/alloc-id:fake:payload
19408     0x11/imm32/alloc-id:fake
19409     _string-loop-if-!=/imm32/name
19410     0x11/imm32/alloc-id:fake
19411     Single-lit-var/imm32/inouts
19412     0/imm32/no-outputs
19413     0/imm32/no-outputs
19414     0x11/imm32/alloc-id:fake
19415     _string_0f_85_jump_label/imm32/subx-name
19416     0/imm32/no-rm32
19417     0/imm32/no-r32
19418     0/imm32/no-imm32
19419     0/imm32/no-imm8
19420     1/imm32/disp32-is-first-inout
19421     0/imm32/no-output
19422     0x11/imm32/alloc-id:fake
19423     _Primitive-loop-if-addr<=-named/imm32/next
19424 _Primitive-loop-if-addr<=-named:  # (payload primitive)
19425     0x11/imm32/alloc-id:fake:payload
19426     0x11/imm32/alloc-id:fake
19427     _string-loop-if-addr<=/imm32/name
19428     0x11/imm32/alloc-id:fake
19429     Single-lit-var/imm32/inouts
19430     0/imm32/no-outputs
19431     0/imm32/no-outputs
19432     0x11/imm32/alloc-id:fake
19433     _string_0f_86_jump_label/imm32/subx-name
19434     0/imm32/no-rm32
19435     0/imm32/no-r32
19436     0/imm32/no-imm32
19437     0/imm32/no-imm8
19438     1/imm32/disp32-is-first-inout
19439     0/imm32/no-output
19440     0x11/imm32/alloc-id:fake
19441     _Primitive-loop-if-addr>-named/imm32/next
19442 _Primitive-loop-if-addr>-named:  # (payload primitive)
19443     0x11/imm32/alloc-id:fake:payload
19444     0x11/imm32/alloc-id:fake
19445     _string-loop-if-addr>/imm32/name
19446     0x11/imm32/alloc-id:fake
19447     Single-lit-var/imm32/inouts
19448     0/imm32/no-outputs
19449     0/imm32/no-outputs
19450     0x11/imm32/alloc-id:fake
19451     _string_0f_87_jump_label/imm32/subx-name
19452     0/imm32/no-rm32
19453     0/imm32/no-r32
19454     0/imm32/no-imm32
19455     0/imm32/no-imm8
19456     1/imm32/disp32-is-first-inout
19457     0/imm32/no-output
19458     0x11/imm32/alloc-id:fake
19459     _Primitive-loop-if-<-named/imm32/next
19460 _Primitive-loop-if-<-named:  # (payload primitive)
19461     0x11/imm32/alloc-id:fake:payload
19462     0x11/imm32/alloc-id:fake
19463     _string-loop-if-</imm32/name
19464     0x11/imm32/alloc-id:fake
19465     Single-lit-var/imm32/inouts
19466     0/imm32/no-outputs
19467     0/imm32/no-outputs
19468     0x11/imm32/alloc-id:fake
19469     _string_0f_8c_jump_label/imm32/subx-name
19470     0/imm32/no-rm32
19471     0/imm32/no-r32
19472     0/imm32/no-imm32
19473     0/imm32/no-imm8
19474     1/imm32/disp32-is-first-inout
19475     0/imm32/no-output
19476     0x11/imm32/alloc-id:fake
19477     _Primitive-loop-if->=-named/imm32/next
19478 _Primitive-loop-if->=-named:  # (payload primitive)
19479     0x11/imm32/alloc-id:fake:payload
19480     0x11/imm32/alloc-id:fake
19481     _string-loop-if->=/imm32/name
19482     0x11/imm32/alloc-id:fake
19483     Single-lit-var/imm32/inouts
19484     0/imm32/no-outputs
19485     0/imm32/no-outputs
19486     0x11/imm32/alloc-id:fake
19487     _string_0f_8d_jump_label/imm32/subx-name
19488     0/imm32/no-rm32
19489     0/imm32/no-r32
19490     0/imm32/no-imm32
19491     0/imm32/no-imm8
19492     1/imm32/disp32-is-first-inout
19493     0/imm32/no-output
19494     0x11/imm32/alloc-id:fake
19495     _Primitive-loop-if-<=-named/imm32/next
19496 _Primitive-loop-if-<=-named:  # (payload primitive)
19497     0x11/imm32/alloc-id:fake:payload
19498     0x11/imm32/alloc-id:fake
19499     _string-loop-if-<=/imm32/name
19500     0x11/imm32/alloc-id:fake
19501     Single-lit-var/imm32/inouts
19502     0/imm32/no-outputs
19503     0/imm32/no-outputs
19504     0x11/imm32/alloc-id:fake
19505     _string_0f_8e_jump_label/imm32/subx-name
19506     0/imm32/no-rm32
19507     0/imm32/no-r32
19508     0/imm32/no-imm32
19509     0/imm32/no-imm8
19510     1/imm32/disp32-is-first-inout
19511     0/imm32/no-output
19512     0x11/imm32/alloc-id:fake
19513     _Primitive-loop-if->-named/imm32/next
19514 _Primitive-loop-if->-named:  # (payload primitive)
19515     0x11/imm32/alloc-id:fake:payload
19516     0x11/imm32/alloc-id:fake
19517     _string-loop-if->/imm32/name
19518     0x11/imm32/alloc-id:fake
19519     Single-lit-var/imm32/inouts
19520     0/imm32/no-outputs
19521     0/imm32/no-outputs
19522     0x11/imm32/alloc-id:fake
19523     _string_0f_8f_jump_label/imm32/subx-name
19524     0/imm32/no-rm32
19525     0/imm32/no-r32
19526     0/imm32/no-imm32
19527     0/imm32/no-imm8
19528     1/imm32/disp32-is-first-inout
19529     0/imm32/no-output
19530     0x11/imm32/alloc-id:fake
19531     _Primitive-loop-named/imm32/next  # we probably don't need an unconditional break
19532 _Primitive-loop-named:  # (payload primitive)
19533     0x11/imm32/alloc-id:fake:payload
19534     0x11/imm32/alloc-id:fake
19535     _string-loop/imm32/name
19536     0x11/imm32/alloc-id:fake
19537     Single-lit-var/imm32/inouts
19538     0/imm32/no-outputs
19539     0/imm32/no-outputs
19540     0x11/imm32/alloc-id:fake
19541     _string_e9_jump_label/imm32/subx-name
19542     0/imm32/no-rm32
19543     0/imm32/no-r32
19544     0/imm32/no-imm32
19545     0/imm32/no-imm8
19546     1/imm32/disp32-is-first-inout
19547     0/imm32/no-output
19548     0/imm32/next
19549     0/imm32/next
19550 
19551 # string literals for Mu instructions
19552 _string-add:  # (payload array byte)
19553     0x11/imm32/alloc-id:fake:payload
19554     # "add"
19555     0x3/imm32/size
19556     0x61/a 0x64/d 0x64/d
19557 _string-address:  # (payload array byte)
19558     0x11/imm32/alloc-id:fake:payload
19559     # "address"
19560     0x7/imm32/size
19561     0x61/a 0x64/d 0x64/d 0x72/r 0x65/e 0x73/s 0x73/s
19562 _string-add-to:  # (payload array byte)
19563     0x11/imm32/alloc-id:fake:payload
19564     # "add-to"
19565     0x6/imm32/size
19566     0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
19567 _string-and:  # (payload array byte)
19568     0x11/imm32/alloc-id:fake:payload
19569     # "and"
19570     0x3/imm32/size
19571     0x61/a 0x6e/n 0x64/d
19572 _string-and-with:  # (payload array byte)
19573     0x11/imm32/alloc-id:fake:payload
19574     # "and-with"
19575     0x8/imm32/size
19576     0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
19577 _string-break:  # (payload array byte)
19578     0x11/imm32/alloc-id:fake:payload
19579     # "break"
19580     0x5/imm32/size
19581     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k
19582 _string-break-if-<:  # (payload array byte)
19583     0x11/imm32/alloc-id:fake:payload
19584     # "break-if-<"
19585     0xa/imm32/size
19586     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
19587 _string-break-if-<=:  # (payload array byte)
19588     0x11/imm32/alloc-id:fake:payload
19589     # "break-if-<="
19590     0xb/imm32/size
19591     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
19592 _string-break-if-=:  # (payload array byte)
19593     0x11/imm32/alloc-id:fake:payload
19594     # "break-if-="
19595     0xa/imm32/size
19596     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
19597 _string-break-if->:  # (payload array byte)
19598     0x11/imm32/alloc-id:fake:payload
19599     # "break-if->"
19600     0xa/imm32/size
19601     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
19602 _string-break-if->=:  # (payload array byte)
19603     0x11/imm32/alloc-id:fake:payload
19604     # "break-if->="
19605     0xb/imm32/size
19606     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
19607 _string-break-if-!=:  # (payload array byte)
19608     0x11/imm32/alloc-id:fake:payload
19609     # "break-if-!="
19610     0xb/imm32/size
19611     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
19612 _string-break-if-addr<:  # (payload array byte)
19613     0x11/imm32/alloc-id:fake:payload
19614     # "break-if-addr<"
19615     0xe/imm32/size
19616     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/<
19617 _string-break-if-addr<=:  # (payload array byte)
19618     0x11/imm32/alloc-id:fake:payload
19619     # "break-if-addr<="
19620     0xf/imm32/size
19621     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/=
19622 _string-break-if-addr>:  # (payload array byte)
19623     0x11/imm32/alloc-id:fake:payload
19624     # "break-if-addr>"
19625     0xe/imm32/size
19626     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/>
19627 _string-break-if-addr>=:  # (payload array byte)
19628     0x11/imm32/alloc-id:fake:payload
19629     # "break-if-addr>="
19630     0xf/imm32/size
19631     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/=
19632 _string-compare:  # (payload array byte)
19633     0x11/imm32/alloc-id:fake:payload
19634     # "compare"
19635     0x7/imm32/size
19636     0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e
19637 _string-copy:  # (payload array byte)
19638     0x11/imm32/alloc-id:fake:payload
19639     # "copy"
19640     0x4/imm32/size
19641     0x63/c 0x6f/o 0x70/p 0x79/y
19642 _string-copy-to:  # (payload array byte)
19643     0x11/imm32/alloc-id:fake:payload
19644     # "copy-to"
19645     0x7/imm32/size
19646     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o
19647 _string-copy-byte:
19648     0x11/imm32/alloc-id:fake:payload
19649     # "copy-byte"
19650     0x9/imm32/size
19651     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e
19652 _string-copy-byte-to:
19653     0x11/imm32/alloc-id:fake:payload
19654     # "copy-byte-to"
19655     0xc/imm32/size
19656     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x74/t 0x6f/o
19657 _string-decrement:  # (payload array byte)
19658     0x11/imm32/alloc-id:fake:payload
19659     # "decrement"
19660     0x9/imm32/size
19661     0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
19662 _string-increment:  # (payload array byte)
19663     0x11/imm32/alloc-id:fake:payload
19664     # "increment"
19665     0x9/imm32/size
19666     0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
19667 _string-loop:  # (payload array byte)
19668     0x11/imm32/alloc-id:fake:payload
19669     # "loop"
19670     0x4/imm32/size
19671     0x6c/l 0x6f/o 0x6f/o 0x70/p
19672 _string-loop-if-<:  # (payload array byte)
19673     0x11/imm32/alloc-id:fake:payload
19674     # "loop-if-<"
19675     0x9/imm32/size
19676     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
19677 _string-loop-if-<=:  # (payload array byte)
19678     0x11/imm32/alloc-id:fake:payload
19679     # "loop-if-<="
19680     0xa/imm32/size
19681     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
19682 _string-loop-if-=:  # (payload array byte)
19683     0x11/imm32/alloc-id:fake:payload
19684     # "loop-if-="
19685     0x9/imm32/size
19686     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
19687 _string-loop-if->:  # (payload array byte)
19688     0x11/imm32/alloc-id:fake:payload
19689     # "loop-if->"
19690     0x9/imm32/size
19691     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
19692 _string-loop-if->=:  # (payload array byte)
19693     0x11/imm32/alloc-id:fake:payload
19694     # "loop-if->="
19695     0xa/imm32/size
19696     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
19697 _string-loop-if-!=:  # (payload array byte)
19698     0x11/imm32/alloc-id:fake:payload
19699     # "loop-if-!="
19700     0xa/imm32/size
19701     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
19702 _string-loop-if-addr<:  # (payload array byte)
19703     0x11/imm32/alloc-id:fake:payload
19704     # "loop-if-addr<"
19705     0xd/imm32/size
19706     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/<
19707 _string-loop-if-addr<=:  # (payload array byte)
19708     0x11/imm32/alloc-id:fake:payload
19709     # "loop-if-addr<="
19710     0xe/imm32/size
19711     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/=
19712 _string-loop-if-addr>:  # (payload array byte)
19713     0x11/imm32/alloc-id:fake:payload
19714     # "loop-if-addr>"
19715     0xd/imm32/size
19716     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/>
19717 _string-loop-if-addr>=:  # (payload array byte)
19718     0x11/imm32/alloc-id:fake:payload
19719     # "loop-if-addr>="
19720     0xe/imm32/size
19721     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/=
19722 _string-multiply:  # (payload array byte)
19723     0x11/imm32/alloc-id:fake:payload
19724     # "multiply"
19725     0x8/imm32/size
19726     0x6d/m 0x75/u 0x6c/l 0x74/t 0x69/i 0x70/p 0x6c/l 0x79/y
19727 _string-or:  # (payload array byte)
19728     0x11/imm32/alloc-id:fake:payload
19729     # "or"
19730     0x2/imm32/size
19731     0x6f/o 0x72/r
19732 _string-or-with:  # (payload array byte)
19733     0x11/imm32/alloc-id:fake:payload
19734     # "or-with"
19735     0x7/imm32/size
19736     0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
19737 _string-subtract:  # (payload array byte)
19738     0x11/imm32/alloc-id:fake:payload
19739     # "subtract"
19740     0x8/imm32/size
19741     0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
19742 _string-subtract-from:  # (payload array byte)
19743     0x11/imm32/alloc-id:fake:payload
19744     # "subtract-from"
19745     0xd/imm32/size
19746     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
19747 _string-xor:  # (payload array byte)
19748     0x11/imm32/alloc-id:fake:payload
19749     # "xor"
19750     0x3/imm32/size
19751     0x78/x 0x6f/o 0x72/r
19752 _string-xor-with:  # (payload array byte)
19753     0x11/imm32/alloc-id:fake:payload
19754     # "xor-with"
19755     0x8/imm32/size
19756     0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
19757 _string-shift-left:  # (payload array byte)
19758     0x11/imm32/alloc-id:fake:payload
19759     # "shift-left"
19760     0xa/imm32/size
19761     0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x2d/dash 0x6c/l 0x65/e 0x66/f 0x74/t
19762 _string-shift-right:  # (payload array byte)
19763     0x11/imm32/alloc-id:fake:payload
19764     # "shift-right"
19765     0xb/imm32/size
19766     0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x2d/dash 0x72/r 0x69/i 0x67/g 0x68/h 0x74/t
19767 _string-shift-right-signed:  # (payload array byte)
19768     0x11/imm32/alloc-id:fake:payload
19769     # "shift-right-signed"
19770     0x12/imm32/size
19771     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
19772 
19773 # string literals for SubX instructions
19774 _string_01_add_to:  # (payload array byte)
19775     0x11/imm32/alloc-id:fake:payload
19776     # "01/add-to"
19777     0x9/imm32/size
19778     0x30/0 0x31/1 0x2f/slash 0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
19779 _string_03_add:  # (payload array byte)
19780     0x11/imm32/alloc-id:fake:payload
19781     # "03/add"
19782     0x6/imm32/size
19783     0x30/0 0x33/3 0x2f/slash 0x61/a 0x64/d 0x64/d
19784 _string_05_add_to_eax:  # (payload array byte)
19785     0x11/imm32/alloc-id:fake:payload
19786     # "05/add-to-eax"
19787     0xd/imm32/size
19788     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
19789 _string_09_or_with:  # (payload array byte)
19790     0x11/imm32/alloc-id:fake:payload
19791     # "09/or-with"
19792     0xa/imm32/size
19793     0x30/0 0x39/9 0x2f/slash 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
19794 _string_0b_or:  # (payload array byte)
19795     0x11/imm32/alloc-id:fake:payload
19796     # "0b/or"
19797     0x5/imm32/size
19798     0x30/0 0x62/b 0x2f/slash 0x6f/o 0x72/r
19799 _string_0d_or_with_eax:  # (payload array byte)
19800     0x11/imm32/alloc-id:fake:payload
19801     # "0d/or-with-eax"
19802     0xe/imm32/size
19803     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
19804 _string_0f_82_jump_label:  # (payload array byte)
19805     0x11/imm32/alloc-id:fake:payload
19806     # "0f 82/jump-if-addr<"
19807     0x13/imm32/size
19808     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/<
19809 _string_0f_82_jump_break:  # (payload array byte)
19810     0x11/imm32/alloc-id:fake:payload
19811     # "0f 82/jump-if-addr< break/disp32"
19812     0x20/imm32/size
19813     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
19814 _string_0f_82_jump_loop:  # (payload array byte)
19815     0x11/imm32/alloc-id:fake:payload
19816     # "0f 82/jump-if-addr< loop/disp32"
19817     0x1f/imm32/size
19818     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
19819 _string_0f_83_jump_label:  # (payload array byte)
19820     0x11/imm32/alloc-id:fake:payload
19821     # "0f 83/jump-if-addr>="
19822     0x14/imm32/size
19823     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/=
19824 _string_0f_83_jump_break:  # (payload array byte)
19825     0x11/imm32/alloc-id:fake:payload
19826     # "0f 83/jump-if-addr>= break/disp32"
19827     0x21/imm32/size
19828     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
19829 _string_0f_83_jump_loop:  # (payload array byte)
19830     0x11/imm32/alloc-id:fake:payload
19831     # "0f 83/jump-if-addr>= loop/disp32"
19832     0x20/imm32/size
19833     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
19834 _string_0f_84_jump_label:  # (payload array byte)
19835     0x11/imm32/alloc-id:fake:payload
19836     # "0f 84/jump-if-="
19837     0xf/imm32/size
19838     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/=
19839 _string_0f_84_jump_break:  # (payload array byte)
19840     0x11/imm32/alloc-id:fake:payload
19841     # "0f 84/jump-if-= break/disp32"
19842     0x1c/imm32/size
19843     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
19844 _string_0f_84_jump_loop:  # (payload array byte)
19845     0x11/imm32/alloc-id:fake:payload
19846     # "0f 84/jump-if-= loop/disp32"
19847     0x1b/imm32/size
19848     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
19849 _string_0f_85_jump_label:  # (payload array byte)
19850     0x11/imm32/alloc-id:fake:payload
19851     # "0f 85/jump-if-!="
19852     0x10/imm32/size
19853     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/=
19854 _string_0f_85_jump_break:  # (payload array byte)
19855     0x11/imm32/alloc-id:fake:payload
19856     # "0f 85/jump-if-!= break/disp32"
19857     0x1d/imm32/size
19858     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
19859 _string_0f_85_jump_loop:  # (payload array byte)
19860     0x11/imm32/alloc-id:fake:payload
19861     # "0f 85/jump-if-!= loop/disp32"
19862     0x1c/imm32/size
19863     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
19864 _string_0f_86_jump_label:  # (payload array byte)
19865     0x11/imm32/alloc-id:fake:payload
19866     # "0f 86/jump-if-addr<="
19867     0x14/imm32/size
19868     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/=
19869 _string_0f_86_jump_break:  # (payload array byte)
19870     0x11/imm32/alloc-id:fake:payload
19871     # "0f 86/jump-if-addr<= break/disp32"
19872     0x21/imm32/size
19873     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
19874 _string_0f_86_jump_loop:  # (payload array byte)
19875     0x11/imm32/alloc-id:fake:payload
19876     # "0f 86/jump-if-addr<= loop/disp32"
19877     0x20/imm32/size
19878     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
19879 _string_0f_87_jump_label:  # (payload array byte)
19880     0x11/imm32/alloc-id:fake:payload
19881     # "0f 87/jump-if-addr>"
19882     0x13/imm32/size
19883     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/>
19884 _string_0f_87_jump_break:  # (payload array byte)
19885     0x11/imm32/alloc-id:fake:payload
19886     # "0f 87/jump-if-addr> break/disp32"
19887     0x20/imm32/size
19888     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
19889 _string_0f_87_jump_loop:  # (payload array byte)
19890     0x11/imm32/alloc-id:fake:payload
19891     # "0f 87/jump-if-addr> loop/disp32"
19892     0x1f/imm32/size
19893     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
19894 _string_0f_8c_jump_label:  # (payload array byte)
19895     0x11/imm32/alloc-id:fake:payload
19896     # "0f 8c/jump-if-<"
19897     0xf/imm32/size
19898     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/<
19899 _string_0f_8c_jump_break:  # (payload array byte)
19900     0x11/imm32/alloc-id:fake:payload
19901     # "0f 8c/jump-if-< break/disp32"
19902     0x1c/imm32/size
19903     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
19904 _string_0f_8c_jump_loop:  # (payload array byte)
19905     0x11/imm32/alloc-id:fake:payload
19906     # "0f 8c/jump-if-< loop/disp32"
19907     0x1b/imm32/size
19908     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
19909 _string_0f_8d_jump_label:  # (payload array byte)
19910     0x11/imm32/alloc-id:fake:payload
19911     # "0f 8d/jump-if->="
19912     0x10/imm32/size
19913     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/=
19914 _string_0f_8d_jump_break:  # (payload array byte)
19915     0x11/imm32/alloc-id:fake:payload
19916     # "0f 8d/jump-if->= break/disp32"
19917     0x1d/imm32/size
19918     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
19919 _string_0f_8d_jump_loop:  # (payload array byte)
19920     0x11/imm32/alloc-id:fake:payload
19921     # "0f 8d/jump-if->= loop/disp32"
19922     0x1c/imm32/size
19923     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
19924 _string_0f_8e_jump_label:  # (payload array byte)
19925     0x11/imm32/alloc-id:fake:payload
19926     # "0f 8e/jump-if-<="
19927     0x10/imm32/size
19928     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/=
19929 _string_0f_8e_jump_break:  # (payload array byte)
19930     0x11/imm32/alloc-id:fake:payload
19931     # "0f 8e/jump-if-<= break/disp32"
19932     0x1d/imm32/size
19933     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
19934 _string_0f_8e_jump_loop:  # (payload array byte)
19935     0x11/imm32/alloc-id:fake:payload
19936     # "0f 8e/jump-if-<= loop/disp32"
19937     0x1c/imm32/size
19938     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
19939 _string_0f_8f_jump_label:  # (payload array byte)
19940     0x11/imm32/alloc-id:fake:payload
19941     # "0f 8f/jump-if->"
19942     0xf/imm32/size
19943     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/>
19944 _string_0f_8f_jump_break:  # (payload array byte)
19945     0x11/imm32/alloc-id:fake:payload
19946     # "0f 8f/jump-if-> break/disp32"
19947     0x1c/imm32/size
19948     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
19949 _string_0f_8f_jump_loop:  # (payload array byte)
19950     0x11/imm32/alloc-id:fake:payload
19951     # "0f 8f/jump-if-> loop/disp32"
19952     0x1b/imm32/size
19953     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
19954 _string_0f_af_multiply:  # (payload array byte)
19955     0x11/imm32/alloc-id:fake:payload
19956     # "0f af/multiply"
19957     0xe/imm32/size
19958     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
19959 _string_21_and_with:  # (payload array byte)
19960     0x11/imm32/alloc-id:fake:payload
19961     # "21/and-with"
19962     0xb/imm32/size
19963     0x32/2 0x31/1 0x2f/slash 0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
19964 _string_23_and:  # (payload array byte)
19965     0x11/imm32/alloc-id:fake:payload
19966     # "23/and"
19967     0x6/imm32/size
19968     0x32/2 0x33/3 0x2f/slash 0x61/a 0x6e/n 0x64/d
19969 _string_25_and_with_eax:  # (payload array byte)
19970     0x11/imm32/alloc-id:fake:payload
19971     # "25/and-with-eax"
19972     0xf/imm32/size
19973     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
19974 _string_29_subtract_from:  # (payload array byte)
19975     0x11/imm32/alloc-id:fake:payload
19976     # "29/subtract-from"
19977     0x10/imm32/size
19978     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
19979 _string_2b_subtract:  # (payload array byte)
19980     0x11/imm32/alloc-id:fake:payload
19981     # "2b/subtract"
19982     0xb/imm32/size
19983     0x32/2 0x62/b 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
19984 _string_2d_subtract_from_eax:  # (payload array byte)
19985     0x11/imm32/alloc-id:fake:payload
19986     # "2d/subtract-from-eax"
19987     0x14/imm32/size
19988     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
19989 _string_31_xor_with:  # (payload array byte)
19990     0x11/imm32/alloc-id:fake:payload
19991     # "31/xor-with"
19992     0xb/imm32/size
19993     0x33/3 0x31/1 0x2f/slash 0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
19994 _string_33_xor:  # (payload array byte)
19995     0x11/imm32/alloc-id:fake:payload
19996     # "33/xor"
19997     0x6/imm32/size
19998     0x33/3 0x33/3 0x2f/slash 0x78/x 0x6f/o 0x72/r
19999 _string_35_xor_with_eax:  # (payload array byte)
20000     0x11/imm32/alloc-id:fake:payload
20001     # "35/xor-with-eax"
20002     0xf/imm32/size
20003     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
20004 _string_39_compare->:  # (payload array byte)
20005     0x11/imm32/alloc-id:fake:payload
20006     # "39/compare->"
20007     0xc/imm32/size
20008     0x33/3 0x39/9 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x2d/dash 0x3e/>
20009 _string_3b_compare<-:  # (payload array byte)
20010     0x11/imm32/alloc-id:fake:payload
20011     # "3b/compare<-"
20012     0xc/imm32/size
20013     0x33/3 0x62/b 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x3c/< 0x2d/dash
20014 _string_3d_compare_eax_with:  # (payload array byte)
20015     0x11/imm32/alloc-id:fake:payload
20016     # "3d/compare-eax-with"
20017     0x13/imm32/size
20018     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
20019 _string_40_increment_eax:  # (payload array byte)
20020     0x11/imm32/alloc-id:fake:payload
20021     # "40/increment-eax"
20022     0x10/imm32/size
20023     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
20024 _string_41_increment_ecx:  # (payload array byte)
20025     0x11/imm32/alloc-id:fake:payload
20026     # "41/increment-ecx"
20027     0x10/imm32/size
20028     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
20029 _string_42_increment_edx:  # (payload array byte)
20030     0x11/imm32/alloc-id:fake:payload
20031     # "42/increment-edx"
20032     0x10/imm32/size
20033     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
20034 _string_43_increment_ebx:  # (payload array byte)
20035     0x11/imm32/alloc-id:fake:payload
20036     # "43/increment-ebx"
20037     0x10/imm32/size
20038     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
20039 _string_46_increment_esi:  # (payload array byte)
20040     0x11/imm32/alloc-id:fake:payload
20041     # "46/increment-esi"
20042     0x10/imm32/size
20043     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
20044 _string_47_increment_edi:  # (payload array byte)
20045     0x11/imm32/alloc-id:fake:payload
20046     # "47/increment-edi"
20047     0x10/imm32/size
20048     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
20049 _string_48_decrement_eax:  # (payload array byte)
20050     0x11/imm32/alloc-id:fake:payload
20051     # "48/decrement-eax"
20052     0x10/imm32/size
20053     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
20054 _string_49_decrement_ecx:  # (payload array byte)
20055     0x11/imm32/alloc-id:fake:payload
20056     # "49/decrement-ecx"
20057     0x10/imm32/size
20058     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
20059 _string_4a_decrement_edx:  # (payload array byte)
20060     0x11/imm32/alloc-id:fake:payload
20061     # "4a/decrement-edx"
20062     0x10/imm32/size
20063     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
20064 _string_4b_decrement_ebx:  # (payload array byte)
20065     0x11/imm32/alloc-id:fake:payload
20066     # "4b/decrement-ebx"
20067     0x10/imm32/size
20068     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
20069 _string_4e_decrement_esi:  # (payload array byte)
20070     0x11/imm32/alloc-id:fake:payload
20071     # "4e/decrement-esi"
20072     0x10/imm32/size
20073     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
20074 _string_4f_decrement_edi:  # (payload array byte)
20075     0x11/imm32/alloc-id:fake:payload
20076     # "4f/decrement-edi"
20077     0x10/imm32/size
20078     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
20079 _string_81_subop_add:  # (payload array byte)
20080     0x11/imm32/alloc-id:fake:payload
20081     # "81 0/subop/add"
20082     0xe/imm32/size
20083     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
20084 _string_81_subop_or:  # (payload array byte)
20085     0x11/imm32/alloc-id:fake:payload
20086     # "81 1/subop/or"
20087     0xd/imm32/size
20088     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
20089 _string_81_subop_and:  # (payload array byte)
20090     0x11/imm32/alloc-id:fake:payload
20091     # "81 4/subop/and"
20092     0xe/imm32/size
20093     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
20094 _string_81_subop_subtract:  # (payload array byte)
20095     0x11/imm32/alloc-id:fake:payload
20096     # "81 5/subop/subtract"
20097     0x13/imm32/size
20098     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
20099 _string_81_subop_xor:  # (payload array byte)
20100     0x11/imm32/alloc-id:fake:payload
20101     # "81 6/subop/xor"
20102     0xe/imm32/size
20103     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
20104 _string_81_subop_compare:  # (payload array byte)
20105     0x11/imm32/alloc-id:fake:payload
20106     # "81 7/subop/compare"
20107     0x12/imm32/size
20108     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
20109 _string_89_<-:  # (payload array byte)
20110     0x11/imm32/alloc-id:fake:payload
20111     # "89/<-"
20112     0x5/imm32/size
20113     0x38/8 0x39/9 0x2f/slash 0x3c/< 0x2d/dash
20114 _string_8b_->:  # (payload array byte)
20115     0x11/imm32/alloc-id:fake:payload
20116     # "8b/->"
20117     0x5/imm32/size
20118     0x38/8 0x62/b 0x2f/slash 0x2d/dash 0x3e/>
20119 _string_8a_copy_byte:
20120     0x11/imm32/alloc-id:fake:payload
20121     # "8a/byte->"
20122     0x9/imm32/size
20123     0x38/8 0x61/a 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x3e/>
20124 _string_88_copy_byte:
20125     0x11/imm32/alloc-id:fake:payload
20126     # "88/byte<-"
20127     0x9/imm32/size
20128     0x38/8 0x38/8 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x3c/< 0x2d/-
20129 _string_8d_copy_address:  # (payload array byte)
20130     0x11/imm32/alloc-id:fake:payload
20131     # "8d/copy-address"
20132     0xf/imm32/size
20133     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
20134 _string_b8_copy_to_eax:  # (payload array byte)
20135     0x11/imm32/alloc-id:fake:payload
20136     # "b8/copy-to-eax"
20137     0xe/imm32/size
20138     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
20139 _string_b9_copy_to_ecx:  # (payload array byte)
20140     0x11/imm32/alloc-id:fake:payload
20141     # "b9/copy-to-ecx"
20142     0xe/imm32/size
20143     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
20144 _string_ba_copy_to_edx:  # (payload array byte)
20145     0x11/imm32/alloc-id:fake:payload
20146     # "ba/copy-to-edx"
20147     0xe/imm32/size
20148     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
20149 _string_bb_copy_to_ebx:  # (payload array byte)
20150     0x11/imm32/alloc-id:fake:payload
20151     # "bb/copy-to-ebx"
20152     0xe/imm32/size
20153     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
20154 _string_be_copy_to_esi:  # (payload array byte)
20155     0x11/imm32/alloc-id:fake:payload
20156     # "be/copy-to-esi"
20157     0xe/imm32/size
20158     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
20159 _string_bf_copy_to_edi:  # (payload array byte)
20160     0x11/imm32/alloc-id:fake:payload
20161     # "bf/copy-to-edi"
20162     0xe/imm32/size
20163     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
20164 _string_c7_subop_copy:  # (payload array byte)
20165     0x11/imm32/alloc-id:fake:payload
20166     # "c7 0/subop/copy"
20167     0xf/imm32/size
20168     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
20169 _string_e9_jump_label:  # (payload array byte)
20170     0x11/imm32/alloc-id:fake:payload
20171     # "e9/jump"
20172     0x7/imm32/size
20173     0x65/e 0x39/9 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p
20174 _string_e9_jump_break:  # (payload array byte)
20175     0x11/imm32/alloc-id:fake:payload
20176     # "e9/jump break/disp32"
20177     0x14/imm32/size
20178     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
20179 _string_e9_jump_loop:  # (payload array byte)
20180     0x11/imm32/alloc-id:fake:payload
20181     # "e9/jump loop/disp32"
20182     0x13/imm32/size
20183     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
20184 _string_ff_subop_increment:  # (payload array byte)
20185     0x11/imm32/alloc-id:fake:payload
20186     # "ff 0/subop/increment"
20187     0x14/imm32/size
20188     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
20189 _string_ff_subop_decrement:  # (payload array byte)
20190     0x11/imm32/alloc-id:fake:payload
20191     # "ff 1/subop/decrement"
20192     0x14/imm32/size
20193     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
20194 _string_c1_subop_shift_left:  # (payload array byte)
20195     0x11/imm32/alloc-id:fake:payload
20196     # "c1/shift 4/subop/left"
20197     0x15/imm32/size
20198     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
20199 _string_c1_subop_shift_right_padding_zeroes:  # (payload array byte)
20200     0x11/imm32/alloc-id:fake:payload
20201     # "c1/shift 5/subop/right-padding-zeroes"
20202     0x25/imm32/size
20203     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
20204 _string_c1_subop_shift_right_preserving_sign:  # (payload array byte)
20205     0x11/imm32/alloc-id:fake:payload
20206     # "c1/shift 7/subop/right-preserving-sign"
20207     0x26/imm32/size
20208     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
20209 
20210 Single-int-var-in-mem:  # (payload list var)
20211     0x11/imm32/alloc-id:fake:payload
20212     0x11/imm32/alloc-id:fake
20213     Int-var-in-mem/imm32
20214     0/imm32/next
20215     0/imm32/next
20216 
20217 Int-var-in-mem:  # (payload var)
20218     0x11/imm32/alloc-id:fake:payload
20219     0/imm32/name
20220     0/imm32/name
20221     0x11/imm32/alloc-id:fake
20222     Type-int/imm32
20223     1/imm32/some-block-depth
20224     1/imm32/some-stack-offset
20225     0/imm32/no-register
20226     0/imm32/no-register
20227 
20228 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
20229 Single-byte-var-in-mem:  # (payload list var)
20230     0x11/imm32/alloc-id:fake:payload
20231     0x11/imm32/alloc-id:fake
20232     Byte-var-in-mem/imm32
20233     0/imm32/next
20234     0/imm32/next
20235 
20236 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
20237 Byte-var-in-mem:  # (payload var)
20238     0x11/imm32/alloc-id:fake:payload
20239     0/imm32/name
20240     0/imm32/name
20241     0x11/imm32/alloc-id:fake
20242     Type-byte/imm32
20243     1/imm32/some-block-depth
20244     1/imm32/some-stack-offset
20245     0/imm32/no-register
20246     0/imm32/no-register
20247 
20248 Two-args-int-stack-int-reg:  # (payload list var)
20249     0x11/imm32/alloc-id:fake:payload
20250     0x11/imm32/alloc-id:fake
20251     Int-var-in-mem/imm32
20252     0x11/imm32/alloc-id:fake
20253     Single-int-var-in-some-register/imm32/next
20254 
20255 Two-int-args-in-regs:  # (payload list var)
20256     0x11/imm32/alloc-id:fake:payload
20257     0x11/imm32/alloc-id:fake
20258     Int-var-in-some-register/imm32
20259     0x11/imm32/alloc-id:fake
20260     Single-int-var-in-some-register/imm32/next
20261 
20262 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
20263 Two-args-byte-stack-byte-reg:  # (payload list var)
20264     0x11/imm32/alloc-id:fake:payload
20265     0x11/imm32/alloc-id:fake
20266     Byte-var-in-mem/imm32
20267     0x11/imm32/alloc-id:fake
20268     Single-byte-var-in-some-register/imm32/next
20269 
20270 Two-args-int-reg-int-stack:  # (payload list var)
20271     0x11/imm32/alloc-id:fake:payload
20272     0x11/imm32/alloc-id:fake
20273     Int-var-in-some-register/imm32
20274     0x11/imm32/alloc-id:fake
20275     Single-int-var-in-mem/imm32/next
20276 
20277 Two-args-int-eax-int-literal:  # (payload list var)
20278     0x11/imm32/alloc-id:fake:payload
20279     0x11/imm32/alloc-id:fake
20280     Int-var-in-eax/imm32
20281     0x11/imm32/alloc-id:fake
20282     Single-lit-var/imm32/next
20283 
20284 Int-var-and-literal:  # (payload list var)
20285     0x11/imm32/alloc-id:fake:payload
20286     0x11/imm32/alloc-id:fake
20287     Int-var-in-mem/imm32
20288     0x11/imm32/alloc-id:fake
20289     Single-lit-var/imm32/next
20290 
20291 Int-var-in-register-and-literal:  # (payload list var)
20292     0x11/imm32/alloc-id:fake:payload
20293     0x11/imm32/alloc-id:fake
20294     Int-var-in-some-register/imm32
20295     0x11/imm32/alloc-id:fake
20296     Single-lit-var/imm32/next
20297 
20298 Single-int-var-in-some-register:  # (payload list var)
20299     0x11/imm32/alloc-id:fake:payload
20300     0x11/imm32/alloc-id:fake
20301     Int-var-in-some-register/imm32
20302     0/imm32/next
20303     0/imm32/next
20304 
20305 Single-addr-var-in-some-register:  # (payload list var)
20306     0x11/imm32/alloc-id:fake:payload
20307     0x11/imm32/alloc-id:fake
20308     Addr-var-in-some-register/imm32
20309     0/imm32/next
20310     0/imm32/next
20311 
20312 Single-byte-var-in-some-register:  # (payload list var)
20313     0x11/imm32/alloc-id:fake:payload
20314     0x11/imm32/alloc-id:fake
20315     Byte-var-in-some-register/imm32
20316     0/imm32/next
20317     0/imm32/next
20318 
20319 Int-var-in-some-register:  # (payload var)
20320     0x11/imm32/alloc-id:fake:payload
20321     0/imm32/name
20322     0/imm32/name
20323     0x11/imm32/alloc-id:fake
20324     Type-int/imm32
20325     1/imm32/some-block-depth
20326     0/imm32/no-stack-offset
20327     0x11/imm32/alloc-id:fake
20328     Any-register/imm32
20329 
20330 Any-register:  # (payload array byte)
20331     0x11/imm32/alloc-id:fake:payload
20332     1/imm32/size
20333     # data
20334     2a/asterisk
20335 
20336 Addr-var-in-some-register:  # (payload var)
20337     0x11/imm32/alloc-id:fake:payload
20338     0/imm32/name
20339     0/imm32/name
20340     0x11/imm32/alloc-id:fake
20341     Type-addr/imm32
20342     1/imm32/some-block-depth
20343     0/imm32/no-stack-offset
20344     0x11/imm32/alloc-id:fake
20345     Any-register/imm32
20346 
20347 Byte-var-in-some-register:  # (payload var)
20348     0x11/imm32/alloc-id:fake:payload
20349     0/imm32/name
20350     0/imm32/name
20351     0x11/imm32/alloc-id:fake
20352     Type-byte/imm32
20353     1/imm32/some-block-depth
20354     0/imm32/no-stack-offset
20355     0x11/imm32/alloc-id:fake
20356     Any-register/imm32
20357 
20358 Single-int-var-in-eax:  # (payload list var)
20359     0x11/imm32/alloc-id:fake:payload
20360     0x11/imm32/alloc-id:fake
20361     Int-var-in-eax/imm32
20362     0/imm32/next
20363     0/imm32/next
20364 
20365 Int-var-in-eax:
20366     0x11/imm32/alloc-id:fake:payload
20367     0/imm32/name
20368     0/imm32/name
20369     0x11/imm32/alloc-id:fake
20370     Type-int/imm32
20371     1/imm32/some-block-depth
20372     0/imm32/no-stack-offset
20373     0x11/imm32/alloc-id:fake
20374     $Register-eax/imm32
20375 
20376 Single-int-var-in-ecx:  # (payload list var)
20377     0x11/imm32/alloc-id:fake:payload
20378     0x11/imm32/alloc-id:fake
20379     Int-var-in-ecx/imm32
20380     0/imm32/next
20381     0/imm32/next
20382 
20383 Int-var-in-ecx:
20384     0x11/imm32/alloc-id:fake:payload
20385     0/imm32/name
20386     0/imm32/name
20387     0x11/imm32/alloc-id:fake
20388     Type-int/imm32
20389     1/imm32/some-block-depth
20390     0/imm32/no-stack-offset
20391     0x11/imm32/alloc-id:fake
20392     $Register-ecx/imm32/register
20393 
20394 Single-int-var-in-edx:  # (payload list var)
20395     0x11/imm32/alloc-id:fake:payload
20396     0x11/imm32/alloc-id:fake
20397     Int-var-in-edx/imm32
20398     0/imm32/next
20399     0/imm32/next
20400 
20401 Int-var-in-edx:  # (payload list var)
20402     0x11/imm32/alloc-id:fake:payload
20403     0/imm32/name
20404     0/imm32/name
20405     0x11/imm32/alloc-id:fake
20406     Type-int/imm32
20407     1/imm32/some-block-depth
20408     0/imm32/no-stack-offset
20409     0x11/imm32/alloc-id:fake
20410     $Register-edx/imm32/register
20411 
20412 Single-int-var-in-ebx:  # (payload list var)
20413     0x11/imm32/alloc-id:fake:payload
20414     0x11/imm32/alloc-id:fake
20415     Int-var-in-ebx/imm32
20416     0/imm32/next
20417     0/imm32/next
20418 
20419 Int-var-in-ebx:  # (payload list var)
20420     0x11/imm32/alloc-id:fake:payload
20421     0/imm32/name
20422     0/imm32/name
20423     0x11/imm32/alloc-id:fake
20424     Type-int/imm32
20425     1/imm32/some-block-depth
20426     0/imm32/no-stack-offset
20427     0x11/imm32/alloc-id:fake
20428     $Register-ebx/imm32/register
20429 
20430 Single-int-var-in-esi:  # (payload list var)
20431     0x11/imm32/alloc-id:fake:payload
20432     0x11/imm32/alloc-id:fake
20433     Int-var-in-esi/imm32
20434     0/imm32/next
20435     0/imm32/next
20436 
20437 Int-var-in-esi:  # (payload list var)
20438     0x11/imm32/alloc-id:fake:payload
20439     0/imm32/name
20440     0/imm32/name
20441     0x11/imm32/alloc-id:fake
20442     Type-int/imm32
20443     1/imm32/some-block-depth
20444     0/imm32/no-stack-offset
20445     0x11/imm32/alloc-id:fake
20446     $Register-esi/imm32/register
20447 
20448 Single-int-var-in-edi:  # (payload list var)
20449     0x11/imm32/alloc-id:fake:payload
20450     0x11/imm32/alloc-id:fake
20451     Int-var-in-edi/imm32
20452     0/imm32/next
20453     0/imm32/next
20454 
20455 Int-var-in-edi:  # (payload list var)
20456     0x11/imm32/alloc-id:fake:payload
20457     0/imm32/name
20458     0/imm32/name
20459     0x11/imm32/alloc-id:fake
20460     Type-int/imm32
20461     1/imm32/some-block-depth
20462     0/imm32/no-stack-offset
20463     0x11/imm32/alloc-id:fake
20464     $Register-edi/imm32/register
20465 
20466 Single-lit-var:  # (payload list var)
20467     0x11/imm32/alloc-id:fake:payload
20468     0x11/imm32/alloc-id:fake
20469     Lit-var/imm32
20470     0/imm32/next
20471     0/imm32/next
20472 
20473 Lit-var:  # (payload var)
20474     0x11/imm32/alloc-id:fake:payload
20475     0/imm32/name
20476     0/imm32/name
20477     0x11/imm32/alloc-id:fake
20478     Type-literal/imm32
20479     1/imm32/some-block-depth
20480     0/imm32/no-stack-offset
20481     0/imm32/no-register
20482     0/imm32/no-register
20483 
20484 Type-int:  # (payload type-tree)
20485     0x11/imm32/alloc-id:fake:payload
20486     1/imm32/is-atom
20487     1/imm32/value:int
20488     0/imm32/left:unused
20489     0/imm32/right:null
20490     0/imm32/right:null
20491 
20492 Type-literal:  # (payload type-tree)
20493     0x11/imm32/alloc-id:fake:payload
20494     1/imm32/is-atom
20495     0/imm32/value:literal
20496     0/imm32/left:unused
20497     0/imm32/right:null
20498     0/imm32/right:null
20499 
20500 Type-addr:  # (payload type-tree)
20501     0x11/imm32/alloc-id:fake:payload
20502     1/imm32/is-atom
20503     2/imm32/value:addr
20504     0/imm32/left:unused
20505     0/imm32/right:null
20506     0/imm32/right:null
20507 
20508 Type-byte:  # (payload type-tree)
20509     0x11/imm32/alloc-id:fake:payload
20510     1/imm32/is-atom
20511     8/imm32/value:byte
20512     0/imm32/left:unused
20513     0/imm32/right:null
20514     0/imm32/right:null
20515 
20516 == code
20517 emit-subx-primitive:  # out: (addr buffered-file), stmt: (addr stmt), primitive: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
20518     # . prologue
20519     55/push-ebp
20520     89/<- %ebp 4/r32/esp
20521     # . save registers
20522     50/push-eax
20523     51/push-ecx
20524     # ecx = primitive
20525     8b/-> *(ebp+0x10) 1/r32/ecx
20526     # emit primitive name
20527     (emit-indent *(ebp+8) *Curr-block-depth)
20528     (lookup *(ecx+0x18) *(ecx+0x1c))  # Primitive-subx-name Primitive-subx-name => eax
20529     (write-buffered *(ebp+8) %eax)
20530     # emit rm32 if necessary
20531     (emit-subx-rm32 *(ebp+8) *(ecx+0x20) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-rm32
20532     # emit r32 if necessary
20533     (emit-subx-r32 *(ebp+8) *(ecx+0x24) *(ebp+0xc))  # Primitive-subx-r32
20534     # emit imm32 if necessary
20535     (emit-subx-imm32 *(ebp+8) *(ecx+0x28) *(ebp+0xc))  # Primitive-subx-imm32
20536     # emit imm8 if necessary
20537     (emit-subx-imm8 *(ebp+8) *(ecx+0x2c) *(ebp+0xc))  # Primitive-subx-imm8
20538     # emit disp32 if necessary
20539     (emit-subx-disp32 *(ebp+8) *(ecx+0x30) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-disp32
20540     (write-buffered *(ebp+8) Newline)
20541 $emit-subx-primitive:end:
20542     # . restore registers
20543     59/pop-to-ecx
20544     58/pop-to-eax
20545     # . epilogue
20546     89/<- %esp 5/r32/ebp
20547     5d/pop-to-ebp
20548     c3/return
20549 
20550 emit-subx-rm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
20551     # . prologue
20552     55/push-ebp
20553     89/<- %ebp 4/r32/esp
20554     # . save registers
20555     50/push-eax
20556     # if (l == 0) return
20557     81 7/subop/compare *(ebp+0xc) 0/imm32
20558     74/jump-if-= $emit-subx-rm32:end/disp8
20559     # var v/eax: (addr stmt-var)
20560     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
20561     (emit-subx-var-as-rm32 *(ebp+8) %eax)
20562 $emit-subx-rm32:end:
20563     # . restore registers
20564     58/pop-to-eax
20565     # . epilogue
20566     89/<- %esp 5/r32/ebp
20567     5d/pop-to-ebp
20568     c3/return
20569 
20570 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)
20571     # . prologue
20572     55/push-ebp
20573     89/<- %ebp 4/r32/esp
20574     # . save registers
20575     51/push-ecx
20576     # eax = l
20577     8b/-> *(ebp+0xc) 0/r32/eax
20578     # ecx = stmt
20579     8b/-> *(ebp+8) 1/r32/ecx
20580     # if (l == 1) return stmt->inouts
20581     {
20582       3d/compare-eax-and 1/imm32
20583       75/jump-if-!= break/disp8
20584 $get-stmt-operand-from-arg-location:1:
20585       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
20586       eb/jump $get-stmt-operand-from-arg-location:end/disp8
20587     }
20588     # if (l == 2) return stmt->inouts->next
20589     {
20590       3d/compare-eax-and 2/imm32
20591       75/jump-if-!= break/disp8
20592 $get-stmt-operand-from-arg-location:2:
20593       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
20594       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
20595       eb/jump $get-stmt-operand-from-arg-location:end/disp8
20596     }
20597     # if (l == 3) return stmt->outputs
20598     {
20599       3d/compare-eax-and 3/imm32
20600       75/jump-if-!= break/disp8
20601 $get-stmt-operand-from-arg-location:3:
20602       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
20603       eb/jump $get-stmt-operand-from-arg-location:end/disp8
20604     }
20605     # abort
20606     e9/jump $get-stmt-operand-from-arg-location:abort/disp32
20607 $get-stmt-operand-from-arg-location:end:
20608     # . restore registers
20609     59/pop-to-ecx
20610     # . epilogue
20611     89/<- %esp 5/r32/ebp
20612     5d/pop-to-ebp
20613     c3/return
20614 
20615 $get-stmt-operand-from-arg-location:abort:
20616     # error("invalid arg-location " eax)
20617     (write-buffered *(ebp+0x10) "invalid arg-location ")
20618     (write-int32-hex-buffered *(ebp+0x10) %eax)
20619     (write-buffered *(ebp+0x10) Newline)
20620     (flush *(ebp+0x10))
20621     (stop *(ebp+0x14) 1)
20622     # never gets here
20623 
20624 emit-subx-r32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
20625     # . prologue
20626     55/push-ebp
20627     89/<- %ebp 4/r32/esp
20628     # . save registers
20629     50/push-eax
20630     51/push-ecx
20631     # if (l == 0) return
20632     81 7/subop/compare *(ebp+0xc) 0/imm32
20633     0f 84/jump-if-= $emit-subx-r32:end/disp32
20634     # var v/eax: (addr stmt-var)
20635     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
20636     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
20637     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
20638     (maybe-get Mu-registers %eax 0xc)  # => eax: (addr register-index)
20639     (write-buffered *(ebp+8) Space)
20640     (write-int32-hex-buffered *(ebp+8) *eax)
20641     (write-buffered *(ebp+8) "/r32")
20642 $emit-subx-r32:end:
20643     # . restore registers
20644     59/pop-to-ecx
20645     58/pop-to-eax
20646     # . epilogue
20647     89/<- %esp 5/r32/ebp
20648     5d/pop-to-ebp
20649     c3/return
20650 
20651 emit-subx-imm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
20652     # . prologue
20653     55/push-ebp
20654     89/<- %ebp 4/r32/esp
20655     # . save registers
20656     50/push-eax
20657     51/push-ecx
20658     # if (l == 0) return
20659     81 7/subop/compare *(ebp+0xc) 0/imm32
20660     0f 84/jump-if-= $emit-subx-imm32:end/disp32
20661     # var v/eax: (handle var)
20662     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
20663     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
20664     (lookup *eax *(eax+4))  # Var-name Var-name => eax
20665     (write-buffered *(ebp+8) Space)
20666     (write-buffered *(ebp+8) %eax)
20667     (write-buffered *(ebp+8) "/imm32")
20668 $emit-subx-imm32:end:
20669     # . restore registers
20670     59/pop-to-ecx
20671     58/pop-to-eax
20672     # . epilogue
20673     89/<- %esp 5/r32/ebp
20674     5d/pop-to-ebp
20675     c3/return
20676 
20677 emit-subx-imm8:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
20678     # . prologue
20679     55/push-ebp
20680     89/<- %ebp 4/r32/esp
20681     # . save registers
20682     50/push-eax
20683     51/push-ecx
20684     # if (l == 0) return
20685     81 7/subop/compare *(ebp+0xc) 0/imm32
20686     0f 84/jump-if-= $emit-subx-imm32:end/disp32
20687     # var v/eax: (handle var)
20688     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
20689     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
20690     (lookup *eax *(eax+4))  # Var-name Var-name => eax
20691     (write-buffered *(ebp+8) Space)
20692     (write-buffered *(ebp+8) %eax)
20693     (write-buffered *(ebp+8) "/imm8")
20694 $emit-subx-imm8:end:
20695     # . restore registers
20696     59/pop-to-ecx
20697     58/pop-to-eax
20698     # . epilogue
20699     89/<- %esp 5/r32/ebp
20700     5d/pop-to-ebp
20701     c3/return
20702 
20703 emit-subx-disp32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
20704     # . prologue
20705     55/push-ebp
20706     89/<- %ebp 4/r32/esp
20707     # . save registers
20708     50/push-eax
20709     51/push-ecx
20710     # if (location == 0) return
20711     81 7/subop/compare *(ebp+0xc) 0/imm32
20712     0f 84/jump-if-= $emit-subx-disp32:end/disp32
20713     # var v/eax: (addr stmt-var)
20714     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
20715     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
20716     (lookup *eax *(eax+4))  # Var-name Var-name => eax
20717     (write-buffered *(ebp+8) Space)
20718     (write-buffered *(ebp+8) %eax)
20719     # hack: if instruction operation starts with "break", emit ":break"
20720     # var name/ecx: (addr array byte) = lookup(stmt->operation)
20721     8b/-> *(ebp+0x10) 0/r32/eax
20722     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
20723     89/<- %ecx 0/r32/eax
20724     {
20725       (string-starts-with? %ecx "break")  # => eax
20726       3d/compare-eax-and 0/imm32/false
20727       74/jump-if-= break/disp8
20728       (write-buffered *(ebp+8) ":break")
20729     }
20730     # hack: if instruction operation starts with "loop", emit ":loop"
20731     {
20732       (string-starts-with? %ecx "loop")  # => eax
20733       3d/compare-eax-and 0/imm32/false
20734       74/jump-if-= break/disp8
20735       (write-buffered *(ebp+8) ":loop")
20736     }
20737     (write-buffered *(ebp+8) "/disp32")
20738 $emit-subx-disp32:end:
20739     # . restore registers
20740     59/pop-to-ecx
20741     58/pop-to-eax
20742     # . epilogue
20743     89/<- %esp 5/r32/ebp
20744     5d/pop-to-ebp
20745     c3/return
20746 
20747 emit-call:  # out: (addr buffered-file), stmt: (addr stmt)
20748     # . prologue
20749     55/push-ebp
20750     89/<- %ebp 4/r32/esp
20751     # . save registers
20752     50/push-eax
20753     51/push-ecx
20754     #
20755     (emit-indent *(ebp+8) *Curr-block-depth)
20756     (write-buffered *(ebp+8) "(")
20757     # ecx = stmt
20758     8b/-> *(ebp+0xc) 1/r32/ecx
20759     # - emit function name
20760     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
20761     (write-buffered *(ebp+8) %eax)
20762     # - emit arguments
20763     # var curr/eax: (addr stmt-var) = lookup(stmt->inouts)
20764     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
20765     {
20766       # if (curr == null) break
20767       3d/compare-eax-and 0/imm32
20768       74/jump-if-= break/disp8
20769       #
20770       (emit-subx-call-operand *(ebp+8) %eax)
20771       # curr = lookup(curr->next)
20772       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
20773       eb/jump loop/disp8
20774     }
20775     #
20776     (write-buffered *(ebp+8) ")\n")
20777 $emit-call:end:
20778     # . restore registers
20779     59/pop-to-ecx
20780     58/pop-to-eax
20781     # . epilogue
20782     89/<- %esp 5/r32/ebp
20783     5d/pop-to-ebp
20784     c3/return
20785 
20786 emit-subx-call-operand:  # out: (addr buffered-file), s: (addr stmt-var)
20787     # shares code with emit-subx-var-as-rm32
20788     # . prologue
20789     55/push-ebp
20790     89/<- %ebp 4/r32/esp
20791     # . save registers
20792     50/push-eax
20793     51/push-ecx
20794     56/push-esi
20795     # ecx = s
20796     8b/-> *(ebp+0xc) 1/r32/ecx
20797     # var operand/esi: (addr var) = lookup(s->value)
20798     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
20799     89/<- %esi 0/r32/eax
20800     # if (operand->register && !s->is-deref?) emit "%__"
20801     {
20802 $emit-subx-call-operand:check-for-register-direct:
20803       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
20804       74/jump-if-= break/disp8
20805       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
20806       75/jump-if-!= break/disp8
20807 $emit-subx-call-operand:register-direct:
20808       (write-buffered *(ebp+8) " %")
20809       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
20810       (write-buffered *(ebp+8) %eax)
20811       e9/jump $emit-subx-call-operand:end/disp32
20812     }
20813     # else if (operand->register && s->is-deref?) emit "*__"
20814     {
20815 $emit-subx-call-operand:check-for-register-indirect:
20816       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
20817       74/jump-if-= break/disp8
20818       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
20819       74/jump-if-= break/disp8
20820 $emit-subx-call-operand:register-indirect:
20821       (emit-subx-call-operand-register-indirect *(ebp+8) %esi)
20822       e9/jump $emit-subx-call-operand:end/disp32
20823     }
20824     # else if (operand->stack-offset) emit "*(ebp+__)"
20825     {
20826       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
20827       74/jump-if-= break/disp8
20828 $emit-subx-call-operand:stack:
20829       (emit-subx-call-operand-stack *(ebp+8) %esi)
20830       e9/jump $emit-subx-call-operand:end/disp32
20831     }
20832     # else if (operand->type == literal) emit "__"
20833     {
20834       (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
20835       81 7/subop/compare *(eax+4) 0/imm32  # Type-tree-left
20836       75/jump-if-!= break/disp8
20837 $emit-subx-call-operand:literal:
20838       (write-buffered *(ebp+8) Space)
20839       (lookup *esi *(esi+4))  # Var-name Var-name => eax
20840       (write-buffered *(ebp+8) %eax)
20841     }
20842 $emit-subx-call-operand:end:
20843     # . restore registers
20844     5e/pop-to-esi
20845     59/pop-to-ecx
20846     58/pop-to-eax
20847     # . epilogue
20848     89/<- %esp 5/r32/ebp
20849     5d/pop-to-ebp
20850     c3/return
20851 
20852 emit-subx-call-operand-register-indirect:  # out: (addr buffered-file), v: (addr var)
20853     # . prologue
20854     55/push-ebp
20855     89/<- %ebp 4/r32/esp
20856     # . save registers
20857     50/push-eax
20858     51/push-ecx
20859     56/push-esi
20860     # esi = v
20861     8b/-> *(ebp+0xc) 6/r32/esi
20862     # var size/ecx: int = size-of-deref(v)
20863     (size-of-deref %esi)  # => eax
20864     89/<- %ecx 0/r32/eax
20865     # var reg-name/esi: (addr array byte) = lookup(v->register)
20866     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
20867     89/<- %esi 0/r32/eax
20868     # TODO: assert size is a multiple of 4
20869     # var i/eax: int = 0
20870     b8/copy-to-eax 0/imm32
20871     {
20872 $emit-subx-call-operand-register-indirect:loop:
20873       # if (i >= size) break
20874       39/compare %eax 1/r32/ecx
20875       7d/jump-if->= break/disp8
20876       # emit " *(" v->register "+" i ")"
20877       (write-buffered *(ebp+8) " *(")
20878       (write-buffered *(ebp+8) %esi)
20879       (write-buffered *(ebp+8) "+")
20880       (write-int32-hex-buffered *(ebp+8) %eax)
20881       (write-buffered *(ebp+8) ")")
20882       # i += 4
20883       05/add-to-eax 4/imm32
20884       #
20885       eb/jump loop/disp8
20886     }
20887 $emit-subx-call-operand-register-indirect:end:
20888     # . restore registers
20889     5e/pop-to-esi
20890     59/pop-to-ecx
20891     58/pop-to-eax
20892     # . epilogue
20893     89/<- %esp 5/r32/ebp
20894     5d/pop-to-ebp
20895     c3/return
20896 
20897 emit-subx-call-operand-stack:  # out: (addr buffered-file), v: (addr var)
20898     # . prologue
20899     55/push-ebp
20900     89/<- %ebp 4/r32/esp
20901     # . save registers
20902     50/push-eax
20903     51/push-ecx
20904     56/push-esi
20905     # esi = v
20906     8b/-> *(ebp+0xc) 6/r32/esi
20907     # var curr/ecx: int = v->offset
20908     8b/-> *(esi+0x14) 1/r32/ecx  # Var-offset
20909     # var max/eax: int = v->offset + size-of(v)
20910     (size-of %esi)  # => eax
20911     # TODO: assert size is a multiple of 4
20912     01/add-to %eax 1/r32/ecx
20913     {
20914 $emit-subx-call-operand-stack:loop:
20915       # if (curr >= max) break
20916       39/compare %ecx 0/r32/eax
20917       7d/jump-if->= break/disp8
20918       # emit " *(ebp+" curr ")"
20919       (write-buffered *(ebp+8) " *(ebp+")
20920       (write-int32-hex-buffered *(ebp+8) %ecx)
20921       (write-buffered *(ebp+8) ")")
20922       # i += 4
20923       81 0/subop/add %ecx 4/imm32
20924       #
20925       eb/jump loop/disp8
20926     }
20927 $emit-subx-call-operand-stack:end:
20928     # . restore registers
20929     5e/pop-to-esi
20930     59/pop-to-ecx
20931     58/pop-to-eax
20932     # . epilogue
20933     89/<- %esp 5/r32/ebp
20934     5d/pop-to-ebp
20935     c3/return
20936 
20937 emit-subx-var-as-rm32:  # out: (addr buffered-file), s: (addr stmt-var)
20938     # . prologue
20939     55/push-ebp
20940     89/<- %ebp 4/r32/esp
20941     # . save registers
20942     50/push-eax
20943     51/push-ecx
20944     56/push-esi
20945     # ecx = s
20946     8b/-> *(ebp+0xc) 1/r32/ecx
20947     # var operand/esi: (addr var) = lookup(s->value)
20948     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
20949     89/<- %esi 0/r32/eax
20950     # if (operand->register && s->is-deref?) emit "*__"
20951     {
20952 $emit-subx-var-as-rm32:check-for-register-indirect:
20953       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
20954       74/jump-if-= break/disp8
20955       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
20956       74/jump-if-= break/disp8
20957 $emit-subx-var-as-rm32:register-indirect:
20958       (write-buffered *(ebp+8) " *")
20959       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
20960       (write-buffered *(ebp+8) %eax)
20961       e9/jump $emit-subx-var-as-rm32:end/disp32
20962     }
20963     # if (operand->register && !s->is-deref?) emit "%__"
20964     {
20965 $emit-subx-var-as-rm32:check-for-register-direct:
20966       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
20967       74/jump-if-= break/disp8
20968       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
20969       75/jump-if-!= break/disp8
20970 $emit-subx-var-as-rm32:register-direct:
20971       (write-buffered *(ebp+8) " %")
20972       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
20973       (write-buffered *(ebp+8) %eax)
20974       e9/jump $emit-subx-var-as-rm32:end/disp32
20975     }
20976     # else if (operand->stack-offset) emit "*(ebp+__)"
20977     {
20978       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
20979       74/jump-if-= break/disp8
20980 $emit-subx-var-as-rm32:stack:
20981       (write-buffered *(ebp+8) Space)
20982       (write-buffered *(ebp+8) "*(ebp+")
20983       (write-int32-hex-buffered *(ebp+8) *(esi+0x14))  # Var-offset
20984       (write-buffered *(ebp+8) ")")
20985     }
20986 $emit-subx-var-as-rm32:end:
20987     # . restore registers
20988     5e/pop-to-esi
20989     59/pop-to-ecx
20990     58/pop-to-eax
20991     # . epilogue
20992     89/<- %esp 5/r32/ebp
20993     5d/pop-to-ebp
20994     c3/return
20995 
20996 find-matching-primitive:  # primitives: (addr primitive), stmt: (addr stmt) -> result/eax: (addr primitive)
20997     # . prologue
20998     55/push-ebp
20999     89/<- %ebp 4/r32/esp
21000     # . save registers
21001     51/push-ecx
21002     # var curr/ecx: (addr primitive) = primitives
21003     8b/-> *(ebp+8) 1/r32/ecx
21004     {
21005 $find-matching-primitive:loop:
21006       # if (curr == null) break
21007       81 7/subop/compare %ecx 0/imm32
21008       74/jump-if-= break/disp8
21009       # if match(curr, stmt) return curr
21010       {
21011         (mu-stmt-matches-primitive? *(ebp+0xc) %ecx)  # => eax
21012         3d/compare-eax-and 0/imm32/false
21013         74/jump-if-= break/disp8
21014         89/<- %eax 1/r32/ecx
21015         eb/jump $find-matching-primitive:end/disp8
21016       }
21017 $find-matching-primitive:next-primitive:
21018       # curr = curr->next
21019       (lookup *(ecx+0x38) *(ecx+0x3c))  # Primitive-next Primitive-next => eax
21020       89/<- %ecx 0/r32/eax
21021       #
21022       e9/jump loop/disp32
21023     }
21024     # return null
21025     b8/copy-to-eax 0/imm32
21026 $find-matching-primitive:end:
21027     # . restore registers
21028     59/pop-to-ecx
21029     # . epilogue
21030     89/<- %esp 5/r32/ebp
21031     5d/pop-to-ebp
21032     c3/return
21033 
21034 mu-stmt-matches-primitive?:  # stmt: (addr stmt), primitive: (addr primitive) -> result/eax: boolean
21035     # A mu stmt matches a primitive if the name matches, all the inout vars
21036     # match, and all the output vars match.
21037     # Vars match if types match and registers match.
21038     # In addition, a stmt output matches a primitive's output if types match
21039     # and the primitive has a wildcard register.
21040     # . prologue
21041     55/push-ebp
21042     89/<- %ebp 4/r32/esp
21043     # . save registers
21044     51/push-ecx
21045     52/push-edx
21046     53/push-ebx
21047     56/push-esi
21048     57/push-edi
21049     # ecx = stmt
21050     8b/-> *(ebp+8) 1/r32/ecx
21051     # edx = primitive
21052     8b/-> *(ebp+0xc) 2/r32/edx
21053     {
21054 $mu-stmt-matches-primitive?:check-name:
21055       # if (primitive->name != stmt->operation) return false
21056       # . var esi: (addr array byte) = lookup(stmt->operation)
21057       (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
21058       89/<- %esi 0/r32/eax
21059       # . var edi: (addr array byte) = lookup(primitive->name)
21060       (lookup *edx *(edx+4))  # Primitive-name Primitive-name => eax
21061       89/<- %edi 0/r32/eax
21062       (string-equal? %esi %edi)  # => eax
21063       3d/compare-eax-and 0/imm32/false
21064       75/jump-if-!= break/disp8
21065       b8/copy-to-eax 0/imm32
21066       e9/jump $mu-stmt-matches-primitive?:end/disp32
21067     }
21068     # var curr/esi: (addr stmt-var) = lookup(stmt->inouts)
21069     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
21070     89/<- %esi 0/r32/eax
21071     # var curr2/edi: (addr list var) = lookup(primitive->inouts)
21072     (lookup *(edx+8) *(edx+0xc))  # Primitive-inouts Primitive-inouts => eax
21073     89/<- %edi 0/r32/eax
21074     {
21075 $mu-stmt-matches-primitive?:inouts-loop:
21076       # if (curr == 0 && curr2 == 0) move on to check outputs
21077       {
21078 $mu-stmt-matches-primitive?:check-both-inouts-null:
21079         81 7/subop/compare %esi 0/imm32
21080         75/jump-if-!= break/disp8
21081 $mu-stmt-matches-primitive?:stmt-inout-null:
21082         81 7/subop/compare %edi 0/imm32
21083         0f 84/jump-if-= $mu-stmt-matches-primitive?:check-outputs/disp32
21084 $mu-stmt-matches-primitive?:stmt-inout-null-and-prim-inout-not-null:
21085         # return false
21086         b8/copy-to-eax 0/imm32/false
21087         e9/jump $mu-stmt-matches-primitive?:end/disp32
21088       }
21089       # if (curr2 == 0) return false
21090       {
21091 $mu-stmt-matches-primitive?:check-prim-inout-null:
21092         81 7/subop/compare %edi 0/imm32
21093         75/jump-if-!= break/disp8
21094 $mu-stmt-matches-primitive?:prim-inout-null:
21095         b8/copy-to-eax 0/imm32/false
21096         e9/jump $mu-stmt-matches-primitive?:end/disp32
21097       }
21098       # if (curr != curr2) return false
21099       {
21100 $mu-stmt-matches-primitive?:check-inouts-match:
21101         (lookup *edi *(edi+4))  # List-value List-value => eax
21102         (operand-matches-primitive? %esi %eax)  # => eax
21103         3d/compare-eax-and 0/imm32/false
21104         75/jump-if-!= break/disp8
21105 $mu-stmt-matches-primitive?:inouts-match:
21106         b8/copy-to-eax 0/imm32/false
21107         e9/jump $mu-stmt-matches-primitive?:end/disp32
21108       }
21109 $mu-stmt-matches-primitive?:next-inout:
21110       # curr = lookup(curr->next)
21111       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
21112       89/<- %esi 0/r32/eax
21113       # curr2 = lookup(curr2->next)
21114       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
21115       89/<- %edi 0/r32/eax
21116       #
21117       e9/jump loop/disp32
21118     }
21119 $mu-stmt-matches-primitive?:check-outputs:
21120     # var curr/esi: (addr stmt-var) = lookup(stmt->outputs)
21121     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
21122     89/<- %esi 0/r32/eax
21123     # var curr2/edi: (addr list var) = lookup(primitive->outputs)
21124     (lookup *(edx+0x10) *(edx+0x14))  # Primitive-outputs Primitive-outputs => eax
21125     89/<- %edi 0/r32/eax
21126     {
21127 $mu-stmt-matches-primitive?:outputs-loop:
21128       # if (curr == 0) return (curr2 == 0)
21129       {
21130 $mu-stmt-matches-primitive?:check-both-outputs-null:
21131         81 7/subop/compare %esi 0/imm32
21132         75/jump-if-!= break/disp8
21133         {
21134 $mu-stmt-matches-primitive?:stmt-output-null:
21135           81 7/subop/compare %edi 0/imm32
21136           75/jump-if-!= break/disp8
21137 $mu-stmt-matches-primitive?:both-outputs-null:
21138           # return true
21139           b8/copy-to-eax 1/imm32
21140           e9/jump $mu-stmt-matches-primitive?:end/disp32
21141         }
21142 $mu-stmt-matches-primitive?:stmt-output-null-and-prim-output-not-null:
21143         # return false
21144         b8/copy-to-eax 0/imm32
21145         e9/jump $mu-stmt-matches-primitive?:end/disp32
21146       }
21147       # if (curr2 == 0) return false
21148       {
21149 $mu-stmt-matches-primitive?:check-prim-output-null:
21150         81 7/subop/compare %edi 0/imm32
21151         75/jump-if-!= break/disp8
21152 $mu-stmt-matches-primitive?:prim-output-is-null:
21153         b8/copy-to-eax 0/imm32
21154         e9/jump $mu-stmt-matches-primitive?:end/disp32
21155       }
21156       # if (curr != curr2) return false
21157       {
21158 $mu-stmt-matches-primitive?:check-outputs-match:
21159         (lookup *edi *(edi+4))  # List-value List-value => eax
21160         (operand-matches-primitive? %esi %eax)  # => eax
21161         3d/compare-eax-and 0/imm32/false
21162         75/jump-if-!= break/disp8
21163 $mu-stmt-matches-primitive?:outputs-match:
21164         b8/copy-to-eax 0/imm32
21165         e9/jump $mu-stmt-matches-primitive?:end/disp32
21166       }
21167 $mu-stmt-matches-primitive?:next-output:
21168       # curr = lookup(curr->next)
21169       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
21170       89/<- %esi 0/r32/eax
21171       # curr2 = lookup(curr2->next)
21172       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
21173       89/<- %edi 0/r32/eax
21174       #
21175       e9/jump loop/disp32
21176     }
21177 $mu-stmt-matches-primitive?:return-true:
21178     b8/copy-to-eax 1/imm32
21179 $mu-stmt-matches-primitive?:end:
21180     # . restore registers
21181     5f/pop-to-edi
21182     5e/pop-to-esi
21183     5b/pop-to-ebx
21184     5a/pop-to-edx
21185     59/pop-to-ecx
21186     # . epilogue
21187     89/<- %esp 5/r32/ebp
21188     5d/pop-to-ebp
21189     c3/return
21190 
21191 operand-matches-primitive?:  # s: (addr stmt-var), prim-var: (addr var) -> result/eax: boolean
21192     # . prologue
21193     55/push-ebp
21194     89/<- %ebp 4/r32/esp
21195     # . save registers
21196     51/push-ecx
21197     52/push-edx
21198     53/push-ebx
21199     56/push-esi
21200     57/push-edi
21201     # ecx = s
21202     8b/-> *(ebp+8) 1/r32/ecx
21203     # var var/esi: (addr var) = lookup(s->value)
21204     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
21205     89/<- %esi 0/r32/eax
21206     # edi = prim-var
21207     8b/-> *(ebp+0xc) 7/r32/edi
21208 $operand-matches-primitive?:check-type:
21209     # if !category-match?(var->type, prim-var->type) return false
21210     # . var vtype/ebx: (addr type-tree) = lookup(var->type)
21211     (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
21212     89/<- %ebx 0/r32/eax
21213     # . var ptype/eax: (addr type-tree) = lookup(prim-var->type)
21214     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
21215     (subx-type-category-match? %ebx %eax)  # => eax
21216     3d/compare-eax-and 0/imm32/false
21217     0f 84/jump-if-= $operand-matches-primitive?:return-false/disp32
21218     {
21219 $operand-matches-primitive?:check-register:
21220       # if prim-var is in memory and var is in register but dereference, match
21221       {
21222         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
21223         0f 85/jump-if-!= break/disp32
21224         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
21225         74/jump-if-= break/disp8
21226         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
21227         74/jump-if-= break/disp8
21228 $operand-matches-primitive?:var-deref-match:
21229         e9/jump $operand-matches-primitive?:return-true/disp32
21230       }
21231       # if prim-var is in register and var is in register but dereference, no match
21232       {
21233         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
21234         0f 84/jump-if-= break/disp32
21235         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
21236         0f 84/jump-if-= break/disp32
21237         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
21238         74/jump-if-= break/disp8
21239 $operand-matches-primitive?:var-deref-no-match:
21240         e9/jump $operand-matches-primitive?:return-false/disp32
21241       }
21242       # return false if var->register doesn't match prim-var->register
21243       {
21244         # if register addresses are equal, it's a match
21245         # var vreg/ebx: (addr array byte) = lookup(var->register)
21246         (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
21247         89/<- %ebx 0/r32/eax
21248         # var preg/ecx: (addr array byte) = lookup(prim-var->register)
21249         (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
21250         89/<- %ecx 0/r32/eax
21251         # if (vreg == preg) break
21252         39/compare %ecx 3/r32/ebx
21253         74/jump-if-= break/disp8
21254 $operand-matches-primitive?:var-register-no-match:
21255         # if either address is 0, return false
21256         81 7/subop/compare %ebx 0/imm32
21257         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
21258         81 7/subop/compare %ecx 0/imm32
21259         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
21260         # if prim-var->register is wildcard, it's a match
21261         (string-equal? %ecx "*")  # Any-register => eax
21262         3d/compare-eax-and 0/imm32/false
21263         75/jump-if-!= break/disp8
21264 $operand-matches-primitive?:wildcard-no-match:
21265         # if string contents aren't equal, return false
21266         (string-equal? %ecx %ebx)  # => eax
21267         3d/compare-eax-and 0/imm32/false
21268         74/jump-if-= $operand-matches-primitive?:return-false/disp8
21269       }
21270     }
21271 $operand-matches-primitive?:return-true:
21272     b8/copy-to-eax 1/imm32/true
21273     eb/jump $operand-matches-primitive?:end/disp8
21274 $operand-matches-primitive?:return-false:
21275     b8/copy-to-eax 0/imm32/false
21276 $operand-matches-primitive?:end:
21277     # . restore registers
21278     5f/pop-to-edi
21279     5e/pop-to-esi
21280     5b/pop-to-ebx
21281     5a/pop-to-edx
21282     59/pop-to-ecx
21283     # . epilogue
21284     89/<- %esp 5/r32/ebp
21285     5d/pop-to-ebp
21286     c3/return
21287 
21288 find-matching-function:  # functions: (addr function), stmt: (addr stmt) -> result/eax: (addr function)
21289     # . prologue
21290     55/push-ebp
21291     89/<- %ebp 4/r32/esp
21292     # . save registers
21293     51/push-ecx
21294     # var curr/ecx: (handle function) = functions
21295     8b/-> *(ebp+8) 1/r32/ecx
21296     {
21297       # if (curr == null) break
21298       81 7/subop/compare %ecx 0/imm32
21299       74/jump-if-= break/disp8
21300 #?       (write-buffered Stderr "iter\n")
21301 #?       (flush Stderr)
21302       # if match(stmt, curr) return curr
21303       {
21304         (mu-stmt-matches-function? *(ebp+0xc) %ecx)  # => eax
21305         3d/compare-eax-and 0/imm32/false
21306         74/jump-if-= break/disp8
21307         89/<- %eax 1/r32/ecx
21308         eb/jump $find-matching-function:end/disp8
21309       }
21310       # curr = curr->next
21311       (lookup *(ecx+0x20) *(ecx+0x24))  # Function-next Function-next => eax
21312       89/<- %ecx 0/r32/eax
21313       #
21314       eb/jump loop/disp8
21315     }
21316     # return null
21317     b8/copy-to-eax 0/imm32
21318 $find-matching-function:end:
21319     # . restore registers
21320     59/pop-to-ecx
21321     # . epilogue
21322     89/<- %esp 5/r32/ebp
21323     5d/pop-to-ebp
21324     c3/return
21325 
21326 # Just compare names; user-defined functions don't support overloading yet.
21327 mu-stmt-matches-function?:  # stmt: (addr stmt1), function: (addr function) -> result/eax: boolean
21328     # . prologue
21329     55/push-ebp
21330     89/<- %ebp 4/r32/esp
21331     # . save registers
21332     51/push-ecx
21333     # return function->name == stmt->operation
21334     # ecx = lookup(stmt->operation)
21335     8b/-> *(ebp+8) 0/r32/eax
21336     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
21337     89/<- %ecx 0/r32/eax
21338     # eax = lookup(function->name)
21339     8b/-> *(ebp+0xc) 0/r32/eax
21340     (lookup *eax *(eax+4))  # Function-name Function-name => eax
21341     (string-equal? %eax %ecx)  # => eax
21342 $mu-stmt-matches-function?:end:
21343     # . restore registers
21344     59/pop-to-ecx
21345     # . epilogue
21346     89/<- %esp 5/r32/ebp
21347     5d/pop-to-ebp
21348     c3/return
21349 
21350 # Type-checking happens elsewhere. This method is for selecting between
21351 # primitives.
21352 subx-type-category-match?:  # a: (addr type-tree), b: (addr type-tree) -> result/eax: boolean
21353     # . prologue
21354     55/push-ebp
21355     89/<- %ebp 4/r32/esp
21356     # . save registers
21357     51/push-ecx
21358     # var alit/ecx: boolean = is-literal-type?(a)
21359     (is-simple-mu-type? *(ebp+8) 0)  # => eax
21360     89/<- %ecx 0/r32/eax
21361     # var blit/eax: boolean = is-literal-type?(b)
21362     (is-simple-mu-type? *(ebp+0xc) 0)  # => eax
21363     # return alit == blit
21364     39/compare %eax 1/r32/ecx
21365     0f 94/set-byte-if-= %al
21366     81 4/subop/and %eax 0xff/imm32
21367 $subx-type-category-match?:end:
21368     # . restore registers
21369     59/pop-to-ecx
21370     # . epilogue
21371     89/<- %esp 5/r32/ebp
21372     5d/pop-to-ebp
21373     c3/return
21374 
21375 is-simple-mu-type?:  # a: (addr type-tree), n: type-id -> result/eax: boolean
21376     # . prologue
21377     55/push-ebp
21378     89/<- %ebp 4/r32/esp
21379     # . save registers
21380     51/push-ecx
21381     # ecx = n
21382     8b/-> *(ebp+0xc) 1/r32/ecx
21383     # return (a->value == n)
21384     8b/-> *(ebp+8) 0/r32/eax
21385     39/compare *(eax+4) 1/r32/ecx  # Type-tree-value
21386     0f 94/set-byte-if-= %al
21387     81 4/subop/and %eax 0xff/imm32
21388 $is-simple-mu-type?:end:
21389     # . restore registers
21390     59/pop-to-ecx
21391     # . epilogue
21392     89/<- %esp 5/r32/ebp
21393     5d/pop-to-ebp
21394     c3/return
21395 
21396 is-mu-addr-type?:  # a: (addr type-tree) -> result/eax: boolean
21397     # . prologue
21398     55/push-ebp
21399     89/<- %ebp 4/r32/esp
21400     # eax = a
21401     8b/-> *(ebp+8) 0/r32/eax
21402     # if (!a->is-atom?) a = a->left
21403     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
21404     {
21405       75/jump-if-!= break/disp8
21406       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
21407     }
21408     # return (a->value == addr)
21409     81 7/subop/compare *(eax+4) 2/imm32/addr  # Type-tree-value
21410     0f 94/set-byte-if-= %al
21411     81 4/subop/and %eax 0xff/imm32
21412 $is-mu-addr-type?:end:
21413     # . epilogue
21414     89/<- %esp 5/r32/ebp
21415     5d/pop-to-ebp
21416     c3/return
21417 
21418 is-mu-array-type?:  # a: (addr type-tree) -> result/eax: boolean
21419     # . prologue
21420     55/push-ebp
21421     89/<- %ebp 4/r32/esp
21422     # eax = a
21423     8b/-> *(ebp+8) 0/r32/eax
21424     # if (!a->is-atom?) a = a->left
21425     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
21426     {
21427       75/jump-if-!= break/disp8
21428       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
21429     }
21430     # return (a->value == array)
21431     81 7/subop/compare *(eax+4) 3/imm32/array  # Type-tree-value
21432     0f 94/set-byte-if-= %al
21433     81 4/subop/and %eax 0xff/imm32
21434 $is-mu-array-type?:end:
21435     # . epilogue
21436     89/<- %esp 5/r32/ebp
21437     5d/pop-to-ebp
21438     c3/return
21439 
21440 is-mu-stream-type?:  # a: (addr type-tree) -> result/eax: boolean
21441     # . prologue
21442     55/push-ebp
21443     89/<- %ebp 4/r32/esp
21444     # eax = a
21445     8b/-> *(ebp+8) 0/r32/eax
21446     # if (!a->is-atom?) a = a->left
21447     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
21448     {
21449       75/jump-if-!= break/disp8
21450       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
21451     }
21452     # return (a->value == stream)
21453     81 7/subop/compare *(eax+4) 0xb/imm32/stream  # Type-tree-value
21454     0f 94/set-byte-if-= %al
21455     81 4/subop/and %eax 0xff/imm32
21456 $is-mu-stream-type?:end:
21457     # . epilogue
21458     89/<- %esp 5/r32/ebp
21459     5d/pop-to-ebp
21460     c3/return
21461 
21462 test-emit-subx-stmt-primitive:
21463     # Primitive operation on a variable on the stack.
21464     #   increment foo
21465     # =>
21466     #   ff 0/subop/increment *(ebp-8)
21467     #
21468     # There's a variable on the var stack as follows:
21469     #   name: 'foo'
21470     #   type: int
21471     #   stack-offset: -8
21472     #
21473     # There's a primitive with this info:
21474     #   name: 'increment'
21475     #   inouts: int/mem
21476     #   value: 'ff 0/subop/increment'
21477     #
21478     # . prologue
21479     55/push-ebp
21480     89/<- %ebp 4/r32/esp
21481     # setup
21482     (clear-stream _test-output-stream)
21483     (clear-stream $_test-output-buffered-file->buffer)
21484     # simulate allocated payloads starting with an initial fake alloc-id (0x11)
21485 $test-emit-subx-stmt-primitive:initialize-type:
21486     # var type/ecx: (payload type-tree) = int
21487     68/push 0/imm32/right:null
21488     68/push 0/imm32/right:null
21489     68/push 0/imm32/left:unused
21490     68/push 1/imm32/value:int
21491     68/push 1/imm32/is-atom?:true
21492     68/push 0x11/imm32/alloc-id:fake:payload
21493     89/<- %ecx 4/r32/esp
21494 $test-emit-subx-stmt-primitive:initialize-var:
21495     # var var-foo/ecx: (payload var) = var(type)
21496     68/push 0/imm32/no-register
21497     68/push 0/imm32/no-register
21498     68/push -8/imm32/stack-offset
21499     68/push 1/imm32/block-depth
21500     51/push-ecx/type
21501     68/push 0x11/imm32/alloc-id:fake
21502     68/push 0/imm32/name
21503     68/push 0/imm32/name
21504     68/push 0x11/imm32/alloc-id:fake:payload
21505     89/<- %ecx 4/r32/esp
21506 $test-emit-subx-stmt-primitive:initialize-var-name:
21507     # var-foo->name = "foo"
21508     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21509     (copy-array Heap "foo" %eax)
21510 $test-emit-subx-stmt-primitive:initialize-stmt-var:
21511     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
21512     68/push 0/imm32/is-deref:false
21513     68/push 0/imm32/next
21514     68/push 0/imm32/next
21515     51/push-ecx/var-foo
21516     68/push 0x11/imm32/alloc-id:fake
21517     68/push 0x11/imm32/alloc-id:fake:payload
21518     89/<- %ebx 4/r32/esp
21519 $test-emit-subx-stmt-primitive:initialize-stmt:
21520     # var stmt/esi: (addr statement)
21521     68/push 0/imm32/no-outputs
21522     68/push 0/imm32/no-outputs
21523     53/push-ebx/inouts
21524     68/push 0x11/imm32/alloc-id:fake
21525     68/push 0/imm32/operation
21526     68/push 0/imm32/operation
21527     68/push 1/imm32/tag
21528     89/<- %esi 4/r32/esp
21529 $test-emit-subx-stmt-primitive:initialize-stmt-operation:
21530     # stmt->operation = "increment"
21531     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21532     (copy-array Heap "increment" %eax)
21533 $test-emit-subx-stmt-primitive:initialize-primitive:
21534     # var primitives/ebx: (addr primitive)
21535     68/push 0/imm32/next
21536     68/push 0/imm32/next
21537     68/push 0/imm32/output-is-write-only
21538     68/push 0/imm32/no-disp32
21539     68/push 0/imm32/no-imm8
21540     68/push 0/imm32/no-imm32
21541     68/push 0/imm32/no-r32
21542     68/push 1/imm32/rm32-is-first-inout
21543     68/push 0/imm32/subx-name
21544     68/push 0/imm32/subx-name
21545     68/push 0/imm32/no-outputs
21546     68/push 0/imm32/no-outputs
21547     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
21548     68/push 0x11/imm32/alloc-id:fake
21549     68/push 0/imm32/name
21550     68/push 0/imm32/name
21551     89/<- %ebx 4/r32/esp
21552 $test-emit-subx-stmt-primitive:initialize-primitive-name:
21553     # primitives->name = "increment"
21554     (copy-array Heap "increment" %ebx)  # Primitive-name
21555 $test-emit-subx-stmt-primitive:initialize-primitive-subx-name:
21556     # primitives->subx-name = "ff 0/subop/increment"
21557     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
21558     (copy-array Heap "ff 0/subop/increment" %eax)
21559     # convert
21560     c7 0/subop/copy *Curr-block-depth 0/imm32
21561     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
21562     (flush _test-output-buffered-file)
21563 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21569     # check output
21570     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-stmt-primitive")
21571     # . epilogue
21572     89/<- %esp 5/r32/ebp
21573     5d/pop-to-ebp
21574     c3/return
21575 
21576 test-emit-subx-stmt-primitive-register:
21577     # Primitive operation on a variable in a register.
21578     #   foo <- increment
21579     # =>
21580     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
21581     #
21582     # There's a variable on the var stack as follows:
21583     #   name: 'foo'
21584     #   type: int
21585     #   register: 'eax'
21586     #
21587     # There's a primitive with this info:
21588     #   name: 'increment'
21589     #   out: int/reg
21590     #   value: 'ff 0/subop/increment'
21591     #
21592     # . prologue
21593     55/push-ebp
21594     89/<- %ebp 4/r32/esp
21595     # setup
21596     (clear-stream _test-output-stream)
21597     (clear-stream $_test-output-buffered-file->buffer)
21598 $test-emit-subx-stmt-primitive-register:initialize-type:
21599     # var type/ecx: (payload type-tree) = int
21600     68/push 0/imm32/right:null
21601     68/push 0/imm32/right:null
21602     68/push 0/imm32/left:unused
21603     68/push 1/imm32/value:int
21604     68/push 1/imm32/is-atom?:true
21605     68/push 0x11/imm32/alloc-id:fake:payload
21606     89/<- %ecx 4/r32/esp
21607 $test-emit-subx-stmt-primitive-register:initialize-var:
21608     # var var-foo/ecx: (payload var)
21609     68/push 0/imm32/register
21610     68/push 0/imm32/register
21611     68/push 0/imm32/no-stack-offset
21612     68/push 1/imm32/block-depth
21613     51/push-ecx
21614     68/push 0x11/imm32/alloc-id:fake
21615     68/push 0/imm32/name
21616     68/push 0/imm32/name
21617     68/push 0x11/imm32/alloc-id:fake:payload
21618     89/<- %ecx 4/r32/esp
21619 $test-emit-subx-stmt-primitive-register:initialize-var-name:
21620     # var-foo->name = "foo"
21621     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21622     (copy-array Heap "foo" %eax)
21623 $test-emit-subx-stmt-primitive-register:initialize-var-register:
21624     # var-foo->register = "eax"
21625     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
21626     (copy-array Heap "eax" %eax)
21627 $test-emit-subx-stmt-primitive-register:initialize-stmt-var:
21628     # var operand/ebx: (payload stmt-var)
21629     68/push 0/imm32/is-deref:false
21630     68/push 0/imm32/next
21631     68/push 0/imm32/next
21632     51/push-ecx/var-foo
21633     68/push 0x11/imm32/alloc-id:fake
21634     68/push 0x11/imm32/alloc-id:fake:payload
21635     89/<- %ebx 4/r32/esp
21636 $test-emit-subx-stmt-primitive-register:initialize-stmt:
21637     # var stmt/esi: (addr statement)
21638     53/push-ebx/outputs
21639     68/push 0x11/imm32/alloc-id:fake
21640     68/push 0/imm32/no-inouts
21641     68/push 0/imm32/no-inouts
21642     68/push 0/imm32/operation
21643     68/push 0/imm32/operation
21644     68/push 1/imm32
21645     89/<- %esi 4/r32/esp
21646 $test-emit-subx-stmt-primitive-register:initialize-stmt-operation:
21647     # stmt->operation = "increment"
21648     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21649     (copy-array Heap "increment" %eax)
21650 $test-emit-subx-stmt-primitive-register:initialize-formal-var:
21651     # var formal-var/ebx: (payload var)
21652     68/push 0/imm32/register
21653     68/push 0/imm32/register
21654     68/push 0/imm32/no-stack-offset
21655     68/push 1/imm32/block-depth
21656     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
21657     68/push 0x11/imm32/alloc-id:fake
21658     68/push 0/imm32/name
21659     68/push 0/imm32/name
21660     68/push 0x11/imm32/alloc-id:fake:payload
21661     89/<- %ebx 4/r32/esp
21662 $test-emit-subx-stmt-primitive-register:initialize-formal-var-name:
21663     # formal-var->name = "dummy"
21664     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
21665     (copy-array Heap "dummy" %eax)
21666 $test-emit-subx-stmt-primitive-register:initialize-formal-register:
21667     # formal-var->register = "*"
21668     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
21669     (copy-array Heap "*" %eax)  # Any-register
21670 $test-emit-subx-stmt-primitive-register:initialize-var-list:
21671     # var formal-outputs/ebx: (payload list var)
21672     68/push 0/imm32/next
21673     68/push 0/imm32/next
21674     53/push-ebx/formal-var
21675     68/push 0x11/imm32/alloc-id:fake
21676     68/push 0x11/imm32/alloc-id:fake:payload
21677     89/<- %ebx 4/r32/esp
21678 $test-emit-subx-stmt-primitive-register:initialize-primitive:
21679     # var primitives/ebx: (addr primitive)
21680     68/push 0/imm32/next
21681     68/push 0/imm32/next
21682     68/push 0/imm32/output-is-write-only
21683     68/push 0/imm32/no-disp32
21684     68/push 0/imm32/no-imm8
21685     68/push 0/imm32/no-imm32
21686     68/push 0/imm32/no-r32
21687     68/push 3/imm32/rm32-is-first-output
21688     68/push 0/imm32/subx-name
21689     68/push 0/imm32/subx-name
21690     53/push-ebx/outputs
21691     68/push 0x11/imm32/alloc-id:fake
21692     68/push 0/imm32/no-inouts
21693     68/push 0/imm32/no-inouts
21694     68/push 0/imm32/name
21695     68/push 0/imm32/name
21696     89/<- %ebx 4/r32/esp
21697 $test-emit-subx-stmt-primitive-register:initialize-primitive-name:
21698     # primitives->name = "increment"
21699     (copy-array Heap "increment" %ebx)  # Primitive-name
21700 $test-emit-subx-stmt-primitive-register:initialize-primitive-subx-name:
21701     # primitives->subx-name = "ff 0/subop/increment"
21702     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
21703     (copy-array Heap "ff 0/subop/increment" %eax)
21704     # convert
21705     c7 0/subop/copy *Curr-block-depth 0/imm32
21706     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
21707     (flush _test-output-buffered-file)
21708 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21714     # check output
21715     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-primitive-register")
21716     # . epilogue
21717     89/<- %esp 5/r32/ebp
21718     5d/pop-to-ebp
21719     c3/return
21720 
21721 test-emit-subx-stmt-select-primitive:
21722     # Select the right primitive between overloads.
21723     #   foo <- increment
21724     # =>
21725     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
21726     #
21727     # There's a variable on the var stack as follows:
21728     #   name: 'foo'
21729     #   type: int
21730     #   register: 'eax'
21731     #
21732     # There's two primitives, as follows:
21733     #   - name: 'increment'
21734     #     out: int/reg
21735     #     value: 'ff 0/subop/increment'
21736     #   - name: 'increment'
21737     #     inout: int/mem
21738     #     value: 'ff 0/subop/increment'
21739     #
21740     # . prologue
21741     55/push-ebp
21742     89/<- %ebp 4/r32/esp
21743     # setup
21744     (clear-stream _test-output-stream)
21745     (clear-stream $_test-output-buffered-file->buffer)
21746 $test-emit-subx-stmt-select-primitive:initialize-type:
21747     # var type/ecx: (payload type-tree) = int
21748     68/push 0/imm32/right:null
21749     68/push 0/imm32/right:null
21750     68/push 0/imm32/left:unused
21751     68/push 1/imm32/value:int
21752     68/push 1/imm32/is-atom?:true
21753     68/push 0x11/imm32/alloc-id:fake:payload
21754     89/<- %ecx 4/r32/esp
21755 $test-emit-subx-stmt-select-primitive:initialize-var:
21756     # var var-foo/ecx: (payload var)
21757     68/push 0/imm32/register
21758     68/push 0/imm32/register
21759     68/push 0/imm32/no-stack-offset
21760     68/push 1/imm32/block-depth
21761     51/push-ecx
21762     68/push 0x11/imm32/alloc-id:fake
21763     68/push 0/imm32/name
21764     68/push 0/imm32/name
21765     68/push 0x11/imm32/alloc-id:fake:payload
21766     89/<- %ecx 4/r32/esp
21767 $test-emit-subx-stmt-select-primitive:initialize-var-name:
21768     # var-foo->name = "foo"
21769     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21770     (copy-array Heap "foo" %eax)
21771 $test-emit-subx-stmt-select-primitive:initialize-var-register:
21772     # var-foo->register = "eax"
21773     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
21774     (copy-array Heap "eax" %eax)
21775 $test-emit-subx-stmt-select-primitive:initialize-stmt-var:
21776     # var operand/ebx: (payload stmt-var)
21777     68/push 0/imm32/is-deref:false
21778     68/push 0/imm32/next
21779     68/push 0/imm32/next
21780     51/push-ecx/var-foo
21781     68/push 0x11/imm32/alloc-id:fake
21782     68/push 0x11/imm32/alloc-id:fake:payload
21783     89/<- %ebx 4/r32/esp
21784 $test-emit-subx-stmt-select-primitive:initialize-stmt:
21785     # var stmt/esi: (addr statement)
21786     53/push-ebx/outputs
21787     68/push 0x11/imm32/alloc-id:fake
21788     68/push 0/imm32/no-inouts
21789     68/push 0/imm32/no-inouts
21790     68/push 0/imm32/operation
21791     68/push 0/imm32/operation
21792     68/push 1/imm32
21793     89/<- %esi 4/r32/esp
21794 $test-emit-subx-stmt-select-primitive:initialize-stmt-operation:
21795     # stmt->operation = "increment"
21796     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21797     (copy-array Heap "increment" %eax)
21798 $test-emit-subx-stmt-select-primitive:initialize-formal-var:
21799     # var formal-var/ebx: (payload var)
21800     68/push 0/imm32/register
21801     68/push 0/imm32/register
21802     68/push 0/imm32/no-stack-offset
21803     68/push 1/imm32/block-depth
21804     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
21805     68/push 0x11/imm32/alloc-id:fake
21806     68/push 0/imm32/name
21807     68/push 0/imm32/name
21808     68/push 0x11/imm32/alloc-id:fake:payload
21809     89/<- %ebx 4/r32/esp
21810 $test-emit-subx-stmt-select-primitive:initialize-formal-var-name:
21811     # formal-var->name = "dummy"
21812     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
21813     (copy-array Heap "dummy" %eax)
21814 $test-emit-subx-stmt-select-primitive:initialize-formal-register:
21815     # formal-var->register = "*"
21816     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
21817     (copy-array Heap "*" %eax)  # Any-register
21818 $test-emit-subx-stmt-select-primitive:initialize-var-list:
21819     # var formal-outputs/ebx: (payload list var)
21820     68/push 0/imm32/next
21821     68/push 0/imm32/next
21822     53/push-ebx/formal-var
21823     68/push 0x11/imm32/alloc-id:fake
21824     68/push 0x11/imm32/alloc-id:fake:payload
21825     89/<- %ebx 4/r32/esp
21826 $test-emit-subx-stmt-select-primitive:initialize-primitive2:
21827     # var primitive2/edi: (payload primitive)
21828     68/push 0/imm32/next
21829     68/push 0/imm32/next
21830     68/push 0/imm32/output-is-write-only
21831     68/push 0/imm32/no-disp32
21832     68/push 0/imm32/no-imm8
21833     68/push 0/imm32/no-imm32
21834     68/push 0/imm32/no-r32
21835     68/push 3/imm32/rm32-is-first-output
21836     68/push 0/imm32/subx-name
21837     68/push 0/imm32/subx-name
21838     53/push-ebx/outputs
21839     68/push 0x11/imm32/alloc-id:fake
21840     68/push 0/imm32/no-inouts
21841     68/push 0/imm32/no-inouts
21842     68/push 0/imm32/name
21843     68/push 0/imm32/name
21844     68/push 0x11/imm32/alloc-id:fake:payload
21845     89/<- %edi 4/r32/esp
21846 $test-emit-subx-stmt-select-primitive:initialize-primitive2-name:
21847     # primitives->name = "increment"
21848     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
21849     (copy-array Heap "increment" %eax)
21850 $test-emit-subx-stmt-select-primitive:initialize-primitive2-subx-name:
21851     # primitives->subx-name = "ff 0/subop/increment"
21852     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
21853     (copy-array Heap "ff 0/subop/increment" %eax)
21854 $test-emit-subx-stmt-select-primitive:initialize-primitive:
21855     # var primitives/ebx: (addr primitive)
21856     57/push-edi
21857     68/push 0x11/imm32/alloc-id:fake
21858     68/push 0/imm32/output-is-write-only
21859     68/push 0/imm32/no-disp32
21860     68/push 0/imm32/no-imm8
21861     68/push 0/imm32/no-imm32
21862     68/push 0/imm32/no-r32
21863     68/push 1/imm32/rm32-is-first-inout
21864     68/push 0/imm32/subx-name
21865     68/push 0/imm32/subx-name
21866     68/push 0/imm32/no-outputs
21867     68/push 0/imm32/no-outputs
21868     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
21869     68/push 0x11/imm32/alloc-id:fake
21870     68/push 0/imm32/name
21871     68/push 0/imm32/name
21872     89/<- %ebx 4/r32/esp
21873 $test-emit-subx-stmt-select-primitive:initialize-primitive-name:
21874     # primitives->name = "increment"
21875     (copy-array Heap "increment" %ebx)  # Primitive-name
21876 $test-emit-subx-stmt-select-primitive:initialize-primitive-subx-name:
21877     # primitives->subx-name = "ff 0/subop/increment"
21878     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
21879     (copy-array Heap "ff 0/subop/increment" %eax)
21880     # convert
21881     c7 0/subop/copy *Curr-block-depth 0/imm32
21882     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
21883     (flush _test-output-buffered-file)
21884 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
21890     # check output
21891     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive")
21892     # . epilogue
21893     89/<- %esp 5/r32/ebp
21894     5d/pop-to-ebp
21895     c3/return
21896 
21897 test-emit-subx-stmt-select-primitive-2:
21898     # Select the right primitive between overloads.
21899     #   increment foo
21900     # =>
21901     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
21902     #
21903     # There's a variable on the var stack as follows:
21904     #   name: 'foo'
21905     #   type: int
21906     #   register: 'eax'
21907     #
21908     # There's two primitives, as follows:
21909     #   - name: 'increment'
21910     #     out: int/reg
21911     #     value: 'ff 0/subop/increment'
21912     #   - name: 'increment'
21913     #     inout: int/mem
21914     #     value: 'ff 0/subop/increment'
21915     #
21916     # . prologue
21917     55/push-ebp
21918     89/<- %ebp 4/r32/esp
21919     # setup
21920     (clear-stream _test-output-stream)
21921     (clear-stream $_test-output-buffered-file->buffer)
21922 $test-emit-subx-stmt-select-primitive-2:initialize-type:
21923     # var type/ecx: (payload type-tree) = int
21924     68/push 0/imm32/right:null
21925     68/push 0/imm32/right:null
21926     68/push 0/imm32/left:unused
21927     68/push 1/imm32/value:int
21928     68/push 1/imm32/is-atom?:true
21929     68/push 0x11/imm32/alloc-id:fake:payload
21930     89/<- %ecx 4/r32/esp
21931 $test-emit-subx-stmt-select-primitive-2:initialize-var:
21932     # var var-foo/ecx: (payload var)
21933     68/push 0/imm32/register
21934     68/push 0/imm32/register
21935     68/push 0/imm32/no-stack-offset
21936     68/push 1/imm32/block-depth
21937     51/push-ecx
21938     68/push 0x11/imm32/alloc-id:fake
21939     68/push 0/imm32/name
21940     68/push 0/imm32/name
21941     68/push 0x11/imm32/alloc-id:fake:payload
21942     89/<- %ecx 4/r32/esp
21943 $test-emit-subx-stmt-select-primitive-2:initialize-var-name:
21944     # var-foo->name = "foo"
21945     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21946     (copy-array Heap "foo" %eax)
21947 $test-emit-subx-stmt-select-primitive-2:initialize-var-register:
21948     # var-foo->register = "eax"
21949     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
21950     (copy-array Heap "eax" %eax)
21951 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-var:
21952     # var operand/ebx: (payload stmt-var)
21953     68/push 0/imm32/is-deref:false
21954     68/push 0/imm32/next
21955     68/push 0/imm32/next
21956     51/push-ecx/var-foo
21957     68/push 0x11/imm32/alloc-id:fake
21958     68/push 0x11/imm32/alloc-id:fake:payload
21959     89/<- %ebx 4/r32/esp
21960 $test-emit-subx-stmt-select-primitive-2:initialize-stmt:
21961     # var stmt/esi: (addr statement)
21962     68/push 0/imm32/no-outputs
21963     68/push 0/imm32/no-outputs
21964     53/push-ebx/inouts
21965     68/push 0x11/imm32/alloc-id:fake
21966     68/push 0/imm32/operation
21967     68/push 0/imm32/operation
21968     68/push 1/imm32
21969     89/<- %esi 4/r32/esp
21970 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-operation:
21971     # stmt->operation = "increment"
21972     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21973     (copy-array Heap "increment" %eax)
21974 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var:
21975     # var formal-var/ebx: (payload var)
21976     68/push 0/imm32/register
21977     68/push 0/imm32/register
21978     68/push 0/imm32/no-stack-offset
21979     68/push 1/imm32/block-depth
21980     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
21981     68/push 0x11/imm32/alloc-id:fake
21982     68/push 0/imm32/name
21983     68/push 0/imm32/name
21984     68/push 0x11/imm32/alloc-id:fake:payload
21985     89/<- %ebx 4/r32/esp
21986 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var-name:
21987     # formal-var->name = "dummy"
21988     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
21989     (copy-array Heap "dummy" %eax)
21990 $test-emit-subx-stmt-select-primitive-2:initialize-formal-register:
21991     # formal-var->register = "*"
21992     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
21993     (copy-array Heap "*" %eax)  # Any-register
21994 $test-emit-subx-stmt-select-primitive-2:initialize-var-list:
21995     # var formal-outputs/ebx: (payload list stmt-var)
21996     68/push 0/imm32/next
21997     68/push 0/imm32/next
21998     53/push-ebx/formal-var
21999     68/push 0x11/imm32/alloc-id:fake
22000     68/push 0x11/imm32/alloc-id:fake:payload
22001     89/<- %ebx 4/r32/esp
22002 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2:
22003     # var primitive2/edi: (payload primitive)
22004     68/push 0/imm32/next
22005     68/push 0/imm32/next
22006     68/push 0/imm32/output-is-write-only
22007     68/push 0/imm32/no-disp32
22008     68/push 0/imm32/no-imm8
22009     68/push 0/imm32/no-imm32
22010     68/push 0/imm32/no-r32
22011     68/push 3/imm32/rm32-is-first-output
22012     68/push 0/imm32/subx-name
22013     68/push 0/imm32/subx-name
22014     53/push-ebx/outputs
22015     68/push 0x11/imm32/alloc-id:fake
22016     68/push 0/imm32/no-inouts
22017     68/push 0/imm32/no-inouts
22018     68/push 0/imm32/name
22019     68/push 0/imm32/name
22020     68/push 0x11/imm32/alloc-id:fake:payload
22021     89/<- %edi 4/r32/esp
22022 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-name:
22023     # primitives->name = "increment"
22024     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
22025     (copy-array Heap "increment" %eax)
22026 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-subx-name:
22027     # primitives->subx-name = "ff 0/subop/increment"
22028     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
22029     (copy-array Heap "ff 0/subop/increment" %eax)
22030 $test-emit-subx-stmt-select-primitive-2:initialize-primitive:
22031     # var primitives/ebx: (addr primitive)
22032     57/push-edi
22033     68/push 0x11/imm32/alloc-id:fake
22034     68/push 0/imm32/output-is-write-only
22035     68/push 0/imm32/no-disp32
22036     68/push 0/imm32/no-imm8
22037     68/push 0/imm32/no-imm32
22038     68/push 0/imm32/no-r32
22039     68/push 1/imm32/rm32-is-first-inout
22040     68/push 0/imm32/subx-name
22041     68/push 0/imm32/subx-name
22042     68/push 0/imm32/no-outputs
22043     68/push 0/imm32/no-outputs
22044     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
22045     68/push 0x11/imm32/alloc-id:fake
22046     68/push 0/imm32/name
22047     68/push 0/imm32/name
22048     89/<- %ebx 4/r32/esp
22049 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-name:
22050     # primitives->name = "increment"
22051     (copy-array Heap "increment" %ebx)  # Primitive-name
22052 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-subx-name:
22053     # primitives->subx-name = "ff 0/subop/increment"
22054     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
22055     (copy-array Heap "ff 0/subop/increment" %eax)
22056     # convert
22057     c7 0/subop/copy *Curr-block-depth 0/imm32
22058     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
22059     (flush _test-output-buffered-file)
22060 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
22066     # check output
22067     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive-2")
22068     # . epilogue
22069     89/<- %esp 5/r32/ebp
22070     5d/pop-to-ebp
22071     c3/return
22072 
22073 test-increment-register:
22074     # Select the right register between overloads.
22075     #   foo <- increment
22076     # =>
22077     #   50/increment-eax
22078     #
22079     # There's a variable on the var stack as follows:
22080     #   name: 'foo'
22081     #   type: int
22082     #   register: 'eax'
22083     #
22084     # Primitives are the global definitions.
22085     #
22086     # . prologue
22087     55/push-ebp
22088     89/<- %ebp 4/r32/esp
22089     # setup
22090     (clear-stream _test-output-stream)
22091     (clear-stream $_test-output-buffered-file->buffer)
22092 $test-increment-register:initialize-type:
22093     # var type/ecx: (payload type-tree) = int
22094     68/push 0/imm32/right:null
22095     68/push 0/imm32/right:null
22096     68/push 0/imm32/left:unused
22097     68/push 1/imm32/value:int
22098     68/push 1/imm32/is-atom?:true
22099     68/push 0x11/imm32/alloc-id:fake:payload
22100     89/<- %ecx 4/r32/esp
22101 $test-increment-register:initialize-var:
22102     # var var-foo/ecx: (payload var)
22103     68/push 0/imm32/register
22104     68/push 0/imm32/register
22105     68/push 0/imm32/no-stack-offset
22106     68/push 1/imm32/block-depth
22107     51/push-ecx
22108     68/push 0x11/imm32/alloc-id:fake
22109     68/push 0/imm32/name
22110     68/push 0/imm32/name
22111     68/push 0x11/imm32/alloc-id:fake:payload
22112     89/<- %ecx 4/r32/esp
22113 $test-increment-register:initialize-var-name:
22114     # var-foo->name = "foo"
22115     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22116     (copy-array Heap "foo" %eax)
22117 $test-increment-register:initialize-var-register:
22118     # var-foo->register = "eax"
22119     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
22120     (copy-array Heap "eax" %eax)
22121 $test-increment-register:initialize-stmt-var:
22122     # var operand/ebx: (payload stmt-var)
22123     68/push 0/imm32/is-deref:false
22124     68/push 0/imm32/next
22125     68/push 0/imm32/next
22126     51/push-ecx/var-foo
22127     68/push 0x11/imm32/alloc-id:fake
22128     68/push 0x11/imm32/alloc-id:fake:payload
22129     89/<- %ebx 4/r32/esp
22130 $test-increment-register:initialize-stmt:
22131     # var stmt/esi: (addr statement)
22132     53/push-ebx/outputs
22133     68/push 0x11/imm32/alloc-id:fake
22134     68/push 0/imm32/no-inouts
22135     68/push 0/imm32/no-inouts
22136     68/push 0/imm32/operation
22137     68/push 0/imm32/operation
22138     68/push 1/imm32
22139     89/<- %esi 4/r32/esp
22140 $test-increment-register:initialize-stmt-operation:
22141     # stmt->operation = "increment"
22142     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22143     (copy-array Heap "increment" %eax)
22144     # convert
22145     c7 0/subop/copy *Curr-block-depth 0/imm32
22146     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22147     (flush _test-output-buffered-file)
22148 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
22154     # check output
22155     (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register")
22156     # . epilogue
22157     89/<- %esp 5/r32/ebp
22158     5d/pop-to-ebp
22159     c3/return
22160 
22161 test-add-reg-to-reg:
22162     #   var1/reg <- add var2/reg
22163     # =>
22164     #   01/add-to %var1 var2
22165     #
22166     # . prologue
22167     55/push-ebp
22168     89/<- %ebp 4/r32/esp
22169     # setup
22170     (clear-stream _test-output-stream)
22171     (clear-stream $_test-output-buffered-file->buffer)
22172 $test-add-reg-to-reg:initialize-type:
22173     # var type/ecx: (payload type-tree) = int
22174     68/push 0/imm32/right:null
22175     68/push 0/imm32/right:null
22176     68/push 0/imm32/left:unused
22177     68/push 1/imm32/value:int
22178     68/push 1/imm32/is-atom?:true
22179     68/push 0x11/imm32/alloc-id:fake:payload
22180     89/<- %ecx 4/r32/esp
22181 $test-add-reg-to-reg:initialize-var1:
22182     # var var1/ecx: (payload var)
22183     68/push 0/imm32/register
22184     68/push 0/imm32/register
22185     68/push 0/imm32/no-stack-offset
22186     68/push 1/imm32/block-depth
22187     51/push-ecx
22188     68/push 0x11/imm32/alloc-id:fake
22189     68/push 0/imm32/name
22190     68/push 0/imm32/name
22191     68/push 0x11/imm32/alloc-id:fake:payload
22192     89/<- %ecx 4/r32/esp
22193 $test-add-reg-to-reg:initialize-var1-name:
22194     # var1->name = "var1"
22195     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22196     (copy-array Heap "var1" %eax)
22197 $test-add-reg-to-reg:initialize-var1-register:
22198     # var1->register = "eax"
22199     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
22200     (copy-array Heap "eax" %eax)
22201 $test-add-reg-to-reg:initialize-var2:
22202     # var var2/edx: (payload var)
22203     68/push 0/imm32/register
22204     68/push 0/imm32/register
22205     68/push 0/imm32/no-stack-offset
22206     68/push 1/imm32/block-depth
22207     ff 6/subop/push *(ecx+0x10)
22208     68/push 0x11/imm32/alloc-id:fake
22209     68/push 0/imm32/name
22210     68/push 0/imm32/name
22211     68/push 0x11/imm32/alloc-id:fake:payload
22212     89/<- %edx 4/r32/esp
22213 $test-add-reg-to-reg:initialize-var2-name:
22214     # var2->name = "var2"
22215     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
22216     (copy-array Heap "var2" %eax)
22217 $test-add-reg-to-reg:initialize-var2-register:
22218     # var2->register = "ecx"
22219     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
22220     (copy-array Heap "ecx" %eax)
22221 $test-add-reg-to-reg:initialize-inouts:
22222     # var inouts/esi: (payload stmt-var) = [var2]
22223     68/push 0/imm32/is-deref:false
22224     68/push 0/imm32/next
22225     68/push 0/imm32/next
22226     52/push-edx/var2
22227     68/push 0x11/imm32/alloc-id:fake
22228     68/push 0x11/imm32/alloc-id:fake:payload
22229     89/<- %esi 4/r32/esp
22230 $test-add-reg-to-reg:initialize-outputs:
22231     # var outputs/edi: (payload stmt-var) = [var1]
22232     68/push 0/imm32/is-deref:false
22233     68/push 0/imm32/next
22234     68/push 0/imm32/next
22235     51/push-ecx/var1
22236     68/push 0x11/imm32/alloc-id:fake
22237     68/push 0x11/imm32/alloc-id:fake:payload
22238     89/<- %edi 4/r32/esp
22239 $test-add-reg-to-reg:initialize-stmt:
22240     # var stmt/esi: (addr statement)
22241     68/push 0/imm32/next
22242     68/push 0/imm32/next
22243     57/push-edi/outputs
22244     68/push 0x11/imm32/alloc-id:fake
22245     56/push-esi/inouts
22246     68/push 0x11/imm32/alloc-id:fake
22247     68/push 0/imm32/operation
22248     68/push 0/imm32/operation
22249     68/push 1/imm32/tag:stmt1
22250     89/<- %esi 4/r32/esp
22251 $test-add-reg-to-reg:initialize-stmt-operation:
22252     # stmt->operation = "add"
22253     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22254     (copy-array Heap "add" %eax)
22255     # convert
22256     c7 0/subop/copy *Curr-block-depth 0/imm32
22257     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22258     (flush _test-output-buffered-file)
22259 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
22265     # check output
22266     (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg")
22267     # . epilogue
22268     89/<- %esp 5/r32/ebp
22269     5d/pop-to-ebp
22270     c3/return
22271 
22272 test-add-reg-to-mem:
22273     #   add-to var1 var2/reg
22274     # =>
22275     #   01/add-to *(ebp+__) var2
22276     #
22277     # . prologue
22278     55/push-ebp
22279     89/<- %ebp 4/r32/esp
22280     # setup
22281     (clear-stream _test-output-stream)
22282     (clear-stream $_test-output-buffered-file->buffer)
22283 $test-add-reg-to-mem:initialize-type:
22284     # var type/ecx: (payload type-tree) = int
22285     68/push 0/imm32/right:null
22286     68/push 0/imm32/right:null
22287     68/push 0/imm32/left:unused
22288     68/push 1/imm32/value:int
22289     68/push 1/imm32/is-atom?:true
22290     68/push 0x11/imm32/alloc-id:fake:payload
22291     89/<- %ecx 4/r32/esp
22292 $test-add-reg-to-mem:initialize-var1:
22293     # var var1/ecx: (payload var)
22294     68/push 0/imm32/register
22295     68/push 0/imm32/register
22296     68/push 8/imm32/stack-offset
22297     68/push 1/imm32/block-depth
22298     51/push-ecx
22299     68/push 0x11/imm32/alloc-id:fake
22300     68/push 0/imm32/name
22301     68/push 0/imm32/name
22302     68/push 0x11/imm32/alloc-id:fake:payload
22303     89/<- %ecx 4/r32/esp
22304 $test-add-reg-to-mem:initialize-var1-name:
22305     # var1->name = "var1"
22306     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22307     (copy-array Heap "var1" %eax)
22308 $test-add-reg-to-mem:initialize-var2:
22309     # var var2/edx: (payload var)
22310     68/push 0/imm32/register
22311     68/push 0/imm32/register
22312     68/push 0/imm32/no-stack-offset
22313     68/push 1/imm32/block-depth
22314     ff 6/subop/push *(ecx+0x10)
22315     68/push 0x11/imm32/alloc-id:fake
22316     68/push 0/imm32/name
22317     68/push 0/imm32/name
22318     68/push 0x11/imm32/alloc-id:fake:payload
22319     89/<- %edx 4/r32/esp
22320 $test-add-reg-to-mem:initialize-var2-name:
22321     # var2->name = "var2"
22322     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
22323     (copy-array Heap "var2" %eax)
22324 $test-add-reg-to-mem:initialize-var2-register:
22325     # var2->register = "ecx"
22326     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
22327     (copy-array Heap "ecx" %eax)
22328 $test-add-reg-to-mem:initialize-inouts:
22329     # var inouts/esi: (payload stmt-var) = [var2]
22330     68/push 0/imm32/is-deref:false
22331     68/push 0/imm32/next
22332     68/push 0/imm32/next
22333     52/push-edx/var2
22334     68/push 0x11/imm32/alloc-id:fake
22335     68/push 0x11/imm32/alloc-id:fake:payload
22336     89/<- %esi 4/r32/esp
22337     # inouts = [var1, var2]
22338     68/push 0/imm32/is-deref:false
22339     56/push-esi/next
22340     68/push 0x11/imm32/alloc-id:fake
22341     51/push-ecx/var1
22342     68/push 0x11/imm32/alloc-id:fake
22343     68/push 0x11/imm32/alloc-id:fake:payload
22344     89/<- %esi 4/r32/esp
22345 $test-add-reg-to-mem:initialize-stmt:
22346     # var stmt/esi: (addr statement)
22347     68/push 0/imm32/next
22348     68/push 0/imm32/next
22349     68/push 0/imm32/outputs
22350     68/push 0/imm32/outputs
22351     56/push-esi/inouts
22352     68/push 0x11/imm32/alloc-id:fake
22353     68/push 0/imm32/operation
22354     68/push 0/imm32/operation
22355     68/push 1/imm32/tag:stmt1
22356     89/<- %esi 4/r32/esp
22357 $test-add-reg-to-mem:initialize-stmt-operation:
22358     # stmt->operation = "add-to"
22359     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22360     (copy-array Heap "add-to" %eax)
22361     # convert
22362     c7 0/subop/copy *Curr-block-depth 0/imm32
22363     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22364     (flush _test-output-buffered-file)
22365 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
22371     # check output
22372     (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem")
22373     # . epilogue
22374     89/<- %esp 5/r32/ebp
22375     5d/pop-to-ebp
22376     c3/return
22377 
22378 test-add-mem-to-reg:
22379     #   var1/reg <- add var2
22380     # =>
22381     #   03/add *(ebp+__) var1
22382     #
22383     # . prologue
22384     55/push-ebp
22385     89/<- %ebp 4/r32/esp
22386     # setup
22387     (clear-stream _test-output-stream)
22388     (clear-stream $_test-output-buffered-file->buffer)
22389 $test-add-mem-to-reg:initialize-type:
22390     # var type/ecx: (payload type-tree) = int
22391     68/push 0/imm32/right:null
22392     68/push 0/imm32/right:null
22393     68/push 0/imm32/left:unused
22394     68/push 1/imm32/value:int
22395     68/push 1/imm32/is-atom?:true
22396     68/push 0x11/imm32/alloc-id:fake:payload
22397     89/<- %ecx 4/r32/esp
22398 $test-add-mem-to-reg:initialize-var:
22399     # var var1/ecx: (payload var)
22400     68/push 0/imm32/register
22401     68/push 0/imm32/register
22402     68/push 0/imm32/no-stack-offset
22403     68/push 1/imm32/block-depth
22404     51/push-ecx
22405     68/push 0x11/imm32/alloc-id:fake
22406     68/push 0/imm32/name
22407     68/push 0/imm32/name
22408     68/push 0x11/imm32/alloc-id:fake:payload
22409     89/<- %ecx 4/r32/esp
22410 $test-add-mem-to-reg:initialize-var-name:
22411     # var1->name = "foo"
22412     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22413     (copy-array Heap "var1" %eax)
22414 $test-add-mem-to-reg:initialize-var-register:
22415     # var1->register = "eax"
22416     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
22417     (copy-array Heap "eax" %eax)
22418 $test-add-mem-to-reg:initialize-var2:
22419     # var var2/edx: (payload var)
22420     68/push 0/imm32/register
22421     68/push 0/imm32/register
22422     68/push 8/imm32/stack-offset
22423     68/push 1/imm32/block-depth
22424     ff 6/subop/push *(ecx+0x10)
22425     68/push 0x11/imm32/alloc-id:fake
22426     68/push 0/imm32/name
22427     68/push 0/imm32/name
22428     68/push 0x11/imm32/alloc-id:fake:payload
22429     89/<- %edx 4/r32/esp
22430 $test-add-mem-to-reg:initialize-var2-name:
22431     # var2->name = "var2"
22432     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
22433     (copy-array Heap "var2" %eax)
22434 $test-add-mem-to-reg:initialize-inouts:
22435     # var inouts/esi: (payload stmt-var) = [var2]
22436     68/push 0/imm32/is-deref:false
22437     68/push 0/imm32/next
22438     68/push 0/imm32/next
22439     52/push-edx/var2
22440     68/push 0x11/imm32/alloc-id:fake
22441     68/push 0x11/imm32/alloc-id:fake:payload
22442     89/<- %esi 4/r32/esp
22443 $test-add-mem-to-reg:initialize-outputs:
22444     # var outputs/edi: (payload stmt-var) = [var1]
22445     68/push 0/imm32/is-deref:false
22446     68/push 0/imm32/next
22447     68/push 0/imm32/next
22448     51/push-ecx/var1
22449     68/push 0x11/imm32/alloc-id:fake
22450     68/push 0x11/imm32/alloc-id:fake:payload
22451     89/<- %edi 4/r32/esp
22452 $test-add-mem-to-reg:initialize-stmt:
22453     # var stmt/esi: (addr statement)
22454     68/push 0/imm32/next
22455     68/push 0/imm32/next
22456     57/push-edi/outputs
22457     68/push 0x11/imm32/alloc-id:fake
22458     56/push-esi/inouts
22459     68/push 0x11/imm32/alloc-id:fake
22460     68/push 0/imm32/operation
22461     68/push 0/imm32/operation
22462     68/push 1/imm32/tag:stmt1
22463     89/<- %esi 4/r32/esp
22464 $test-add-mem-to-reg:initialize-stmt-operation:
22465     # stmt->operation = "add"
22466     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22467     (copy-array Heap "add" %eax)
22468     # convert
22469     c7 0/subop/copy *Curr-block-depth 0/imm32
22470     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22471     (flush _test-output-buffered-file)
22472 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
22478     # check output
22479     (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg")
22480     # . epilogue
22481     89/<- %esp 5/r32/ebp
22482     5d/pop-to-ebp
22483     c3/return
22484 
22485 test-add-literal-to-eax:
22486     #   var1/eax <- add 0x34
22487     # =>
22488     #   05/add-to-eax 0x34/imm32
22489     #
22490     # . prologue
22491     55/push-ebp
22492     89/<- %ebp 4/r32/esp
22493     # setup
22494     (clear-stream _test-output-stream)
22495     (clear-stream $_test-output-buffered-file->buffer)
22496 $test-add-literal-to-eax:initialize-var-type:
22497     # var type/ecx: (payload type-tree) = int
22498     68/push 0/imm32/right:null
22499     68/push 0/imm32/right:null
22500     68/push 0/imm32/left:unused
22501     68/push 1/imm32/value:int
22502     68/push 1/imm32/is-atom?:true
22503     68/push 0x11/imm32/alloc-id:fake:payload
22504     89/<- %ecx 4/r32/esp
22505 $test-add-literal-to-eax:initialize-var:
22506     # var v/ecx: (payload var)
22507     68/push 0/imm32/register
22508     68/push 0/imm32/register
22509     68/push 0/imm32/no-stack-offset
22510     68/push 1/imm32/block-depth
22511     51/push-ecx
22512     68/push 0x11/imm32/alloc-id:fake
22513     68/push 0/imm32/name
22514     68/push 0/imm32/name
22515     68/push 0x11/imm32/alloc-id:fake:payload
22516     89/<- %ecx 4/r32/esp
22517 $test-add-literal-to-eax:initialize-var-name:
22518     # v->name = "v"
22519     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22520     (copy-array Heap "v" %eax)
22521 $test-add-literal-to-eax:initialize-var-register:
22522     # v->register = "eax"
22523     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
22524     (copy-array Heap "eax" %eax)
22525 $test-add-literal-to-eax:initialize-literal-type:
22526     # var type/edx: (payload type-tree) = literal
22527     68/push 0/imm32/right:null
22528     68/push 0/imm32/right:null
22529     68/push 0/imm32/left:unused
22530     68/push 0/imm32/value:literal
22531     68/push 1/imm32/is-atom?:true
22532     68/push 0x11/imm32/alloc-id:fake:payload
22533     89/<- %edx 4/r32/esp
22534 $test-add-literal-to-eax:initialize-literal:
22535     # var l/edx: (payload var)
22536     68/push 0/imm32/register
22537     68/push 0/imm32/register
22538     68/push 0/imm32/no-stack-offset
22539     68/push 1/imm32/block-depth
22540     52/push-edx
22541     68/push 0x11/imm32/alloc-id:fake
22542     68/push 0/imm32/name
22543     68/push 0/imm32/name
22544     68/push 0x11/imm32/alloc-id:fake:payload
22545     89/<- %edx 4/r32/esp
22546 $test-add-literal-to-eax:initialize-literal-value:
22547     # l->name = "0x34"
22548     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
22549     (copy-array Heap "0x34" %eax)
22550 $test-add-literal-to-eax:initialize-inouts:
22551     # var inouts/esi: (payload stmt-var) = [l]
22552     68/push 0/imm32/is-deref:false
22553     68/push 0/imm32/next
22554     68/push 0/imm32/next
22555     52/push-edx/l
22556     68/push 0x11/imm32/alloc-id:fake
22557     68/push 0x11/imm32/alloc-id:fake:payload
22558     89/<- %esi 4/r32/esp
22559 $test-add-literal-to-eax:initialize-outputs:
22560     # var outputs/edi: (payload stmt-var) = [v]
22561     68/push 0/imm32/is-deref:false
22562     68/push 0/imm32/next
22563     68/push 0/imm32/next
22564     51/push-ecx/v
22565     68/push 0x11/imm32/alloc-id:fake
22566     68/push 0x11/imm32/alloc-id:fake:payload
22567     89/<- %edi 4/r32/esp
22568 $test-add-literal-to-eax:initialize-stmt:
22569     # var stmt/esi: (addr statement)
22570     68/push 0/imm32/next
22571     68/push 0/imm32/next
22572     57/push-edi/outputs
22573     68/push 0x11/imm32/alloc-id:fake
22574     56/push-esi/inouts
22575     68/push 0x11/imm32/alloc-id:fake
22576     68/push 0/imm32/operation
22577     68/push 0/imm32/operation
22578     68/push 1/imm32/tag:stmt1
22579     89/<- %esi 4/r32/esp
22580 $test-add-literal-to-eax:initialize-stmt-operation:
22581     # stmt->operation = "add"
22582     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22583     (copy-array Heap "add" %eax)
22584     # convert
22585     c7 0/subop/copy *Curr-block-depth 0/imm32
22586     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22587     (flush _test-output-buffered-file)
22588 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
22594     # check output
22595     (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax")
22596     # . epilogue
22597     89/<- %esp 5/r32/ebp
22598     5d/pop-to-ebp
22599     c3/return
22600 
22601 test-add-literal-to-reg:
22602     #   var1/ecx <- add 0x34
22603     # =>
22604     #   81 0/subop/add %ecx 0x34/imm32
22605     #
22606     # . prologue
22607     55/push-ebp
22608     89/<- %ebp 4/r32/esp
22609     # setup
22610     (clear-stream _test-output-stream)
22611     (clear-stream $_test-output-buffered-file->buffer)
22612 $test-add-literal-to-reg:initialize-var-type:
22613     # var type/ecx: (payload type-tree) = int
22614     68/push 0/imm32/right:null
22615     68/push 0/imm32/right:null
22616     68/push 0/imm32/left:unused
22617     68/push 1/imm32/value:int
22618     68/push 1/imm32/is-atom?:true
22619     68/push 0x11/imm32/alloc-id:fake:payload
22620     89/<- %ecx 4/r32/esp
22621 $test-add-literal-to-reg:initialize-var:
22622     # var v/ecx: (payload var)
22623     68/push 0/imm32/register
22624     68/push 0/imm32/register
22625     68/push 0/imm32/no-stack-offset
22626     68/push 1/imm32/block-depth
22627     51/push-ecx
22628     68/push 0x11/imm32/alloc-id:fake
22629     68/push 0/imm32/name
22630     68/push 0/imm32/name
22631     68/push 0x11/imm32/alloc-id:fake:payload
22632     89/<- %ecx 4/r32/esp
22633 $test-add-literal-to-reg:initialize-var-name:
22634     # v->name = "v"
22635     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22636     (copy-array Heap "v" %eax)
22637 $test-add-literal-to-reg:initialize-var-register:
22638     # v->register = "ecx"
22639     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
22640     (copy-array Heap "ecx" %eax)
22641 $test-add-literal-to-reg:initialize-literal-type:
22642     # var type/edx: (payload type-tree) = literal
22643     68/push 0/imm32/right:null
22644     68/push 0/imm32/right:null
22645     68/push 0/imm32/left:unused
22646     68/push 0/imm32/value:literal
22647     68/push 1/imm32/is-atom?:true
22648     68/push 0x11/imm32/alloc-id:fake:payload
22649     89/<- %edx 4/r32/esp
22650 $test-add-literal-to-reg:initialize-literal:
22651     # var l/edx: (payload var)
22652     68/push 0/imm32/register
22653     68/push 0/imm32/register
22654     68/push 0/imm32/no-stack-offset
22655     68/push 1/imm32/block-depth
22656     52/push-edx
22657     68/push 0x11/imm32/alloc-id:fake
22658     68/push 0/imm32/name
22659     68/push 0/imm32/name
22660     68/push 0x11/imm32/alloc-id:fake:payload
22661     89/<- %edx 4/r32/esp
22662 $test-add-literal-to-reg:initialize-literal-value:
22663     # l->name = "0x34"
22664     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
22665     (copy-array Heap "0x34" %eax)
22666 $test-add-literal-to-reg:initialize-inouts:
22667     # var inouts/esi: (payload stmt-var) = [l]
22668     68/push 0/imm32/is-deref:false
22669     68/push 0/imm32/next
22670     68/push 0/imm32/next
22671     52/push-edx/l
22672     68/push 0x11/imm32/alloc-id:fake
22673     68/push 0x11/imm32/alloc-id:fake:payload
22674     89/<- %esi 4/r32/esp
22675 $test-add-literal-to-reg:initialize-outputs:
22676     # var outputs/edi: (payload stmt-var) = [v]
22677     68/push 0/imm32/is-deref:false
22678     68/push 0/imm32/next
22679     68/push 0/imm32/next
22680     51/push-ecx/v
22681     68/push 0x11/imm32/alloc-id:fake
22682     68/push 0x11/imm32/alloc-id:fake:payload
22683     89/<- %edi 4/r32/esp
22684 $test-add-literal-to-reg:initialize-stmt:
22685     # var stmt/esi: (addr statement)
22686     68/push 0/imm32/next
22687     68/push 0/imm32/next
22688     57/push-edi/outputs
22689     68/push 0x11/imm32/alloc-id:fake
22690     56/push-esi/inouts
22691     68/push 0x11/imm32/alloc-id:fake
22692     68/push 0/imm32/operation
22693     68/push 0/imm32/operation
22694     68/push 1/imm32/tag:stmt1
22695     89/<- %esi 4/r32/esp
22696 $test-add-literal-to-reg:initialize-stmt-operation:
22697     # stmt->operation = "add"
22698     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22699     (copy-array Heap "add" %eax)
22700     # convert
22701     c7 0/subop/copy *Curr-block-depth 0/imm32
22702     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22703     (flush _test-output-buffered-file)
22704 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
22710     # check output
22711     (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg")
22712     # . epilogue
22713     89/<- %esp 5/r32/ebp
22714     5d/pop-to-ebp
22715     c3/return
22716 
22717 test-add-literal-to-mem:
22718     #   add-to var1, 0x34
22719     # =>
22720     #   81 0/subop/add %eax 0x34/imm32
22721     #
22722     # . prologue
22723     55/push-ebp
22724     89/<- %ebp 4/r32/esp
22725     # setup
22726     (clear-stream _test-output-stream)
22727     (clear-stream $_test-output-buffered-file->buffer)
22728 $test-add-literal-to-mem:initialize-type:
22729     # var type/ecx: (payload type-tree) = int
22730     68/push 0/imm32/right:null
22731     68/push 0/imm32/right:null
22732     68/push 0/imm32/left:unused
22733     68/push 1/imm32/value:int
22734     68/push 1/imm32/is-atom?:true
22735     68/push 0x11/imm32/alloc-id:fake:payload
22736     89/<- %ecx 4/r32/esp
22737 $test-add-literal-to-mem:initialize-var1:
22738     # var var1/ecx: (payload var)
22739     68/push 0/imm32/register
22740     68/push 0/imm32/register
22741     68/push 8/imm32/stack-offset
22742     68/push 1/imm32/block-depth
22743     51/push-ecx
22744     68/push 0x11/imm32/alloc-id:fake
22745     68/push 0/imm32/name
22746     68/push 0/imm32/name
22747     68/push 0x11/imm32/alloc-id:fake:payload
22748     89/<- %ecx 4/r32/esp
22749 $test-add-literal-to-mem:initialize-var1-name:
22750     # var1->name = "var1"
22751     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22752     (copy-array Heap "var1" %eax)
22753 $test-add-literal-to-mem:initialize-literal-type:
22754     # var type/edx: (payload type-tree) = literal
22755     68/push 0/imm32/right:null
22756     68/push 0/imm32/right:null
22757     68/push 0/imm32/left:unused
22758     68/push 0/imm32/value:literal
22759     68/push 1/imm32/is-atom?:true
22760     68/push 0x11/imm32/alloc-id:fake:payload
22761     89/<- %edx 4/r32/esp
22762 $test-add-literal-to-mem:initialize-literal:
22763     # var l/edx: (payload var)
22764     68/push 0/imm32/register
22765     68/push 0/imm32/register
22766     68/push 0/imm32/no-stack-offset
22767     68/push 1/imm32/block-depth
22768     52/push-edx
22769     68/push 0x11/imm32/alloc-id:fake
22770     68/push 0/imm32/name
22771     68/push 0/imm32/name
22772     68/push 0x11/imm32/alloc-id:fake:payload
22773     89/<- %edx 4/r32/esp
22774 $test-add-literal-to-mem:initialize-literal-value:
22775     # l->name = "0x34"
22776     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
22777     (copy-array Heap "0x34" %eax)
22778 $test-add-literal-to-mem:initialize-inouts:
22779     # var inouts/esi: (payload stmt-var) = [l]
22780     68/push 0/imm32/is-deref:false
22781     68/push 0/imm32/next
22782     68/push 0/imm32/next
22783     52/push-edx/l
22784     68/push 0x11/imm32/alloc-id:fake
22785     68/push 0x11/imm32/alloc-id:fake:payload
22786     89/<- %esi 4/r32/esp
22787     # var inouts = (handle stmt-var) = [var1, var2]
22788     68/push 0/imm32/is-deref:false
22789     56/push-esi/next
22790     68/push 0x11/imm32/alloc-id:fake
22791     51/push-ecx/var1
22792     68/push 0x11/imm32/alloc-id:fake
22793     68/push 0x11/imm32/alloc-id:fake:payload
22794     89/<- %esi 4/r32/esp
22795 $test-add-literal-to-mem:initialize-stmt:
22796     # var stmt/esi: (addr statement)
22797     68/push 0/imm32/next
22798     68/push 0/imm32/next
22799     68/push 0/imm32/outputs
22800     68/push 0/imm32/outputs
22801     56/push-esi/inouts
22802     68/push 0x11/imm32/alloc-id:fake
22803     68/push 0/imm32/operation
22804     68/push 0/imm32/operation
22805     68/push 1/imm32/tag:stmt1
22806     89/<- %esi 4/r32/esp
22807 $test-add-literal-to-mem:initialize-stmt-operation:
22808     # stmt->operation = "add-to"
22809     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22810     (copy-array Heap "add-to" %eax)
22811     # convert
22812     c7 0/subop/copy *Curr-block-depth 0/imm32
22813     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22814     (flush _test-output-buffered-file)
22815 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
22821     # check output
22822     (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem")
22823     # . epilogue
22824     89/<- %esp 5/r32/ebp
22825     5d/pop-to-ebp
22826     c3/return
22827 
22828 test-shift-reg-by-literal:
22829     #   var1/ecx <- shift-left 2
22830     # =>
22831     #   c1/shift 4/subop/left %ecx 2/imm8
22832     #
22833     # . prologue
22834     55/push-ebp
22835     89/<- %ebp 4/r32/esp
22836     # setup
22837     (clear-stream _test-output-stream)
22838     (clear-stream $_test-output-buffered-file->buffer)
22839 $test-shift-reg-by-literal:initialize-var-type:
22840     # var type/ecx: (payload type-tree) = int
22841     68/push 0/imm32/right:null
22842     68/push 0/imm32/right:null
22843     68/push 0/imm32/left:unused
22844     68/push 1/imm32/value:int
22845     68/push 1/imm32/is-atom?:true
22846     68/push 0x11/imm32/alloc-id:fake:payload
22847     89/<- %ecx 4/r32/esp
22848 $test-shift-reg-by-literal:initialize-var:
22849     # var v/ecx: (payload var)
22850     68/push 0/imm32/register
22851     68/push 0/imm32/register
22852     68/push 0/imm32/no-stack-offset
22853     68/push 1/imm32/block-depth
22854     51/push-ecx
22855     68/push 0x11/imm32/alloc-id:fake
22856     68/push 0/imm32/name
22857     68/push 0/imm32/name
22858     68/push 0x11/imm32/alloc-id:fake:payload
22859     89/<- %ecx 4/r32/esp
22860 $test-shift-reg-by-literal:initialize-var-name:
22861     # v->name = "v"
22862     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22863     (copy-array Heap "v" %eax)
22864 $test-shift-reg-by-literal:initialize-var-register:
22865     # v->register = "ecx"
22866     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
22867     (copy-array Heap "ecx" %eax)
22868 $test-shift-reg-by-literal:initialize-literal-type:
22869     # var type/edx: (payload type-tree) = literal
22870     68/push 0/imm32/right:null
22871     68/push 0/imm32/right:null
22872     68/push 0/imm32/left:unused
22873     68/push 0/imm32/value:literal
22874     68/push 1/imm32/is-atom?:true
22875     68/push 0x11/imm32/alloc-id:fake:payload
22876     89/<- %edx 4/r32/esp
22877 $test-shift-reg-by-literal:initialize-literal:
22878     # var l/edx: (payload var)
22879     68/push 0/imm32/register
22880     68/push 0/imm32/register
22881     68/push 0/imm32/no-stack-offset
22882     68/push 1/imm32/block-depth
22883     52/push-edx
22884     68/push 0x11/imm32/alloc-id:fake
22885     68/push 0/imm32/name
22886     68/push 0/imm32/name
22887     68/push 0x11/imm32/alloc-id:fake:payload
22888     89/<- %edx 4/r32/esp
22889 $test-shift-reg-by-literal:initialize-literal-value:
22890     # l->name = "2"
22891     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
22892     (copy-array Heap "2" %eax)
22893 $test-shift-reg-by-literal:initialize-inouts:
22894     # var inouts/esi: (payload stmt-var) = [l]
22895     68/push 0/imm32/is-deref:false
22896     68/push 0/imm32/next
22897     68/push 0/imm32/next
22898     52/push-edx/l
22899     68/push 0x11/imm32/alloc-id:fake
22900     68/push 0x11/imm32/alloc-id:fake:payload
22901     89/<- %esi 4/r32/esp
22902 $test-shift-reg-by-literal:initialize-outputs:
22903     # var outputs/edi: (payload stmt-var) = [v]
22904     68/push 0/imm32/is-deref:false
22905     68/push 0/imm32/next
22906     68/push 0/imm32/next
22907     51/push-ecx/v
22908     68/push 0x11/imm32/alloc-id:fake
22909     68/push 0x11/imm32/alloc-id:fake:payload
22910     89/<- %edi 4/r32/esp
22911 $test-shift-reg-by-literal:initialize-stmt:
22912     # var stmt/esi: (addr statement)
22913     68/push 0/imm32/next
22914     68/push 0/imm32/next
22915     57/push-edi/outputs
22916     68/push 0x11/imm32/alloc-id:fake
22917     56/push-esi/inouts
22918     68/push 0x11/imm32/alloc-id:fake
22919     68/push 0/imm32/operation
22920     68/push 0/imm32/operation
22921     68/push 1/imm32/tag:stmt1
22922     89/<- %esi 4/r32/esp
22923 $test-shift-reg-by-literal:initialize-stmt-operation:
22924     # stmt->operation = "shift-left"
22925     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22926     (copy-array Heap "shift-left" %eax)
22927     # convert
22928     c7 0/subop/copy *Curr-block-depth 0/imm32
22929     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22930     (flush _test-output-buffered-file)
22931 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
22937     # check output
22938     (check-next-stream-line-equal _test-output-stream "c1/shift 4/subop/left %ecx 2/imm8" "F - test-shift-reg-by-literal")
22939     # . epilogue
22940     89/<- %esp 5/r32/ebp
22941     5d/pop-to-ebp
22942     c3/return
22943 
22944 test-shift-mem-by-literal:
22945     #   shift-left var 3
22946     # =>
22947     #   c1/shift 4/subop/left *(ebp+8) 3/imm8
22948     #
22949     # . prologue
22950     55/push-ebp
22951     89/<- %ebp 4/r32/esp
22952     # setup
22953     (clear-stream _test-output-stream)
22954     (clear-stream $_test-output-buffered-file->buffer)
22955 $test-shift-mem-by-literal:initialize-type:
22956     # var type/ecx: (payload type-tree) = int
22957     68/push 0/imm32/right:null
22958     68/push 0/imm32/right:null
22959     68/push 0/imm32/left:unused
22960     68/push 1/imm32/value:int
22961     68/push 1/imm32/is-atom?:true
22962     68/push 0x11/imm32/alloc-id:fake:payload
22963     89/<- %ecx 4/r32/esp
22964 $test-shift-mem-by-literal:initialize-var1:
22965     # var var1/ecx: (payload var)
22966     68/push 0/imm32/register
22967     68/push 0/imm32/register
22968     68/push 8/imm32/stack-offset
22969     68/push 1/imm32/block-depth
22970     51/push-ecx
22971     68/push 0x11/imm32/alloc-id:fake
22972     68/push 0/imm32/name
22973     68/push 0/imm32/name
22974     68/push 0x11/imm32/alloc-id:fake:payload
22975     89/<- %ecx 4/r32/esp
22976 $test-shift-mem-by-literal:initialize-var1-name:
22977     # var1->name = "var1"
22978     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22979     (copy-array Heap "var1" %eax)
22980 $test-shift-mem-by-literal:initialize-literal-type:
22981     # var type/edx: (payload type-tree) = literal
22982     68/push 0/imm32/right:null
22983     68/push 0/imm32/right:null
22984     68/push 0/imm32/left:unused
22985     68/push 0/imm32/value:literal
22986     68/push 1/imm32/is-atom?:true
22987     68/push 0x11/imm32/alloc-id:fake:payload
22988     89/<- %edx 4/r32/esp
22989 $test-shift-mem-by-literal:initialize-literal:
22990     # var l/edx: (payload var)
22991     68/push 0/imm32/register
22992     68/push 0/imm32/register
22993     68/push 0/imm32/no-stack-offset
22994     68/push 1/imm32/block-depth
22995     52/push-edx
22996     68/push 0x11/imm32/alloc-id:fake
22997     68/push 0/imm32/name
22998     68/push 0/imm32/name
22999     68/push 0x11/imm32/alloc-id:fake:payload
23000     89/<- %edx 4/r32/esp
23001 $test-shift-mem-by-literal:initialize-literal-value:
23002     # l->name = "3"
23003     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
23004     (copy-array Heap "3" %eax)
23005 $test-shift-mem-by-literal:initialize-inouts:
23006     # var inouts/esi: (payload stmt-var) = [l]
23007     68/push 0/imm32/is-deref:false
23008     68/push 0/imm32/next
23009     68/push 0/imm32/next
23010     52/push-edx/l
23011     68/push 0x11/imm32/alloc-id:fake
23012     68/push 0x11/imm32/alloc-id:fake:payload
23013     89/<- %esi 4/r32/esp
23014     # var inouts = (handle stmt-var) = [var1, var2]
23015     68/push 0/imm32/is-deref:false
23016     56/push-esi/next
23017     68/push 0x11/imm32/alloc-id:fake
23018     51/push-ecx/var1
23019     68/push 0x11/imm32/alloc-id:fake
23020     68/push 0x11/imm32/alloc-id:fake:payload
23021     89/<- %esi 4/r32/esp
23022 $test-shift-mem-by-literal:initialize-stmt:
23023     # var stmt/esi: (addr statement)
23024     68/push 0/imm32/next
23025     68/push 0/imm32/next
23026     68/push 0/imm32/outputs
23027     68/push 0/imm32/outputs
23028     56/push-esi/inouts
23029     68/push 0x11/imm32/alloc-id:fake
23030     68/push 0/imm32/operation
23031     68/push 0/imm32/operation
23032     68/push 1/imm32/tag:stmt1
23033     89/<- %esi 4/r32/esp
23034 $test-shift-mem-by-literal:initialize-stmt-operation:
23035     # stmt->operation = "shift-left"
23036     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23037     (copy-array Heap "shift-left" %eax)
23038     # convert
23039     c7 0/subop/copy *Curr-block-depth 0/imm32
23040     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
23041     (flush _test-output-buffered-file)
23042 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
23048     # check output
23049     (check-next-stream-line-equal _test-output-stream "c1/shift 4/subop/left *(ebp+0x00000008) 3/imm8" "F - test-shift-mem-by-literal")
23050     # . epilogue
23051     89/<- %esp 5/r32/ebp
23052     5d/pop-to-ebp
23053     c3/return
23054 
23055 test-compare-reg-with-reg:
23056     #   compare var1/ecx, var2/eax
23057     # =>
23058     #   39/compare %ecx 0/r32/eax
23059     #
23060     # . prologue
23061     55/push-ebp
23062     89/<- %ebp 4/r32/esp
23063     # setup
23064     (clear-stream _test-output-stream)
23065     (clear-stream $_test-output-buffered-file->buffer)
23066 $test-compare-reg-with-reg:initialize-type:
23067     # var type/ecx: (payload type-tree) = int
23068     68/push 0/imm32/right:null
23069     68/push 0/imm32/right:null
23070     68/push 0/imm32/left:unused
23071     68/push 1/imm32/value:int
23072     68/push 1/imm32/is-atom?:true
23073     68/push 0x11/imm32/alloc-id:fake:payload
23074     89/<- %ecx 4/r32/esp
23075 $test-compare-reg-with-reg:initialize-var1:
23076     # var var1/ecx: (payload var)
23077     68/push 0/imm32/register
23078     68/push 0/imm32/register
23079     68/push 0/imm32/no-stack-offset
23080     68/push 1/imm32/block-depth
23081     51/push-ecx
23082     68/push 0x11/imm32/alloc-id:fake
23083     68/push 0/imm32/name
23084     68/push 0/imm32/name
23085     68/push 0x11/imm32/alloc-id:fake:payload
23086     89/<- %ecx 4/r32/esp
23087 $test-compare-reg-with-reg:initialize-var1-name:
23088     # var1->name = "var1"
23089     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23090     (copy-array Heap "var1" %eax)
23091 $test-compare-reg-with-reg:initialize-var1-register:
23092     # var1->register = "ecx"
23093     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
23094     (copy-array Heap "ecx" %eax)
23095 $test-compare-reg-with-reg:initialize-var2:
23096     # var var2/edx: (payload var)
23097     68/push 0/imm32/register
23098     68/push 0/imm32/register
23099     68/push 0/imm32/no-stack-offset
23100     68/push 1/imm32/block-depth
23101     ff 6/subop/push *(ecx+0x10)
23102     68/push 0x11/imm32/alloc-id:fake
23103     68/push 0/imm32/name
23104     68/push 0/imm32/name
23105     68/push 0x11/imm32/alloc-id:fake:payload
23106     89/<- %edx 4/r32/esp
23107 $test-compare-reg-with-reg:initialize-var2-name:
23108     # var2->name = "var2"
23109     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
23110     (copy-array Heap "var2" %eax)
23111 $test-compare-reg-with-reg:initialize-var2-register:
23112     # var2->register = "eax"
23113     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
23114     (copy-array Heap "eax" %eax)
23115 $test-compare-reg-with-reg:initialize-inouts:
23116     # var inouts/esi: (payload stmt-var) = [var2]
23117     68/push 0/imm32/is-deref:false
23118     68/push 0/imm32/next
23119     68/push 0/imm32/next
23120     52/push-edx/var2
23121     68/push 0x11/imm32/alloc-id:fake
23122     68/push 0x11/imm32/alloc-id:fake:payload
23123     89/<- %esi 4/r32/esp
23124     # inouts = [var1, var2]
23125     68/push 0/imm32/is-deref:false
23126     56/push-esi/next
23127     68/push 0x11/imm32/alloc-id:fake
23128     51/push-ecx/var1
23129     68/push 0x11/imm32/alloc-id:fake
23130     68/push 0x11/imm32/alloc-id:fake:payload
23131     89/<- %esi 4/r32/esp
23132 $test-compare-reg-with-reg:initialize-stmt:
23133     # var stmt/esi: (addr statement)
23134     68/push 0/imm32/next
23135     68/push 0/imm32/next
23136     68/push 0/imm32/outputs
23137     68/push 0/imm32/outputs
23138     56/push-esi/inouts
23139     68/push 0x11/imm32/alloc-id:fake
23140     68/push 0/imm32/operation
23141     68/push 0/imm32/operation
23142     68/push 1/imm32/tag:stmt1
23143     89/<- %esi 4/r32/esp
23144 $test-compare-reg-with-reg:initialize-stmt-operation:
23145     # stmt->operation = "compare"
23146     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23147     (copy-array Heap "compare" %eax)
23148     # convert
23149     c7 0/subop/copy *Curr-block-depth 0/imm32
23150     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
23151     (flush _test-output-buffered-file)
23152 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
23158     # check output
23159     (check-next-stream-line-equal _test-output-stream "39/compare-> %ecx 0x00000000/r32" "F - test-compare-reg-with-reg")
23160     # . epilogue
23161     89/<- %esp 5/r32/ebp
23162     5d/pop-to-ebp
23163     c3/return
23164 
23165 test-compare-mem-with-reg:
23166     #   compare var1, var2/eax
23167     # =>
23168     #   39/compare *(ebp+___) 0/r32/eax
23169     #
23170     # . prologue
23171     55/push-ebp
23172     89/<- %ebp 4/r32/esp
23173     # setup
23174     (clear-stream _test-output-stream)
23175     (clear-stream $_test-output-buffered-file->buffer)
23176 $test-compare-mem-with-reg:initialize-type:
23177     # var type/ecx: (payload type-tree) = int
23178     68/push 0/imm32/right:null
23179     68/push 0/imm32/right:null
23180     68/push 0/imm32/left:unused
23181     68/push 1/imm32/value:int
23182     68/push 1/imm32/is-atom?:true
23183     68/push 0x11/imm32/alloc-id:fake:payload
23184     89/<- %ecx 4/r32/esp
23185 $test-compare-mem-with-reg:initialize-var1:
23186     # var var1/ecx: (payload var)
23187     68/push 0/imm32/register
23188     68/push 0/imm32/register
23189     68/push 8/imm32/stack-offset
23190     68/push 1/imm32/block-depth
23191     51/push-ecx
23192     68/push 0x11/imm32/alloc-id:fake
23193     68/push 0/imm32/name
23194     68/push 0/imm32/name
23195     68/push 0x11/imm32/alloc-id:fake:payload
23196     89/<- %ecx 4/r32/esp
23197 $test-compare-mem-with-reg:initialize-var1-name:
23198     # var1->name = "var1"
23199     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23200     (copy-array Heap "var1" %eax)
23201 $test-compare-mem-with-reg:initialize-var2:
23202     # var var2/edx: (payload var)
23203     68/push 0/imm32/register
23204     68/push 0/imm32/register
23205     68/push 0/imm32/no-stack-offset
23206     68/push 1/imm32/block-depth
23207     ff 6/subop/push *(ecx+0x10)
23208     68/push 0x11/imm32/alloc-id:fake
23209     68/push 0/imm32/name
23210     68/push 0/imm32/name
23211     68/push 0x11/imm32/alloc-id:fake:payload
23212     89/<- %edx 4/r32/esp
23213 $test-compare-mem-with-reg:initialize-var2-name:
23214     # var2->name = "var2"
23215     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
23216     (copy-array Heap "var2" %eax)
23217 $test-compare-mem-with-reg:initialize-var2-register:
23218     # var2->register = "eax"
23219     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
23220     (copy-array Heap "eax" %eax)
23221 $test-compare-mem-with-reg:initialize-inouts:
23222     # var inouts/esi: (payload stmt-var) = [var2]
23223     68/push 0/imm32/is-deref:false
23224     68/push 0/imm32/next
23225     68/push 0/imm32/next
23226     52/push-edx/var2
23227     68/push 0x11/imm32/alloc-id:fake
23228     68/push 0x11/imm32/alloc-id:fake:payload
23229     89/<- %esi 4/r32/esp
23230     # inouts = [var1, var2]
23231     68/push 0/imm32/is-deref:false
23232     56/push-esi/next
23233     68/push 0x11/imm32/alloc-id:fake
23234     51/push-ecx/var1
23235     68/push 0x11/imm32/alloc-id:fake
23236     68/push 0x11/imm32/alloc-id:fake:payload
23237     89/<- %esi 4/r32/esp
23238 $test-compare-mem-with-reg:initialize-stmt:
23239     # var stmt/esi: (addr statement)
23240     68/push 0/imm32/next
23241     68/push 0/imm32/next
23242     68/push 0/imm32/outputs
23243     68/push 0/imm32/outputs
23244     56/push-esi/inouts
23245     68/push 0x11/imm32/alloc-id:fake
23246     68/push 0/imm32/operation
23247     68/push 0/imm32/operation
23248     68/push 1/imm32/tag:stmt1
23249     89/<- %esi 4/r32/esp
23250 $test-compare-mem-with-reg:initialize-stmt-operation:
23251     # stmt->operation = "compare"
23252     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23253     (copy-array Heap "compare" %eax)
23254     # convert
23255     c7 0/subop/copy *Curr-block-depth 0/imm32
23256     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
23257     (flush _test-output-buffered-file)
23258 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
23264     # check output
23265     (check-next-stream-line-equal _test-output-stream "39/compare-> *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-mem-with-reg")
23266     # . epilogue
23267     89/<- %esp 5/r32/ebp
23268     5d/pop-to-ebp
23269     c3/return
23270 
23271 test-compare-reg-with-mem:
23272     #   compare var1/eax, var2
23273     # =>
23274     #   3b/compare<- *(ebp+___) 0/r32/eax
23275     #
23276     # . prologue
23277     55/push-ebp
23278     89/<- %ebp 4/r32/esp
23279     # setup
23280     (clear-stream _test-output-stream)
23281     (clear-stream $_test-output-buffered-file->buffer)
23282 $test-compare-reg-with-mem:initialize-type:
23283     # var type/ecx: (payload type-tree) = int
23284     68/push 0/imm32/right:null
23285     68/push 0/imm32/right:null
23286     68/push 0/imm32/left:unused
23287     68/push 1/imm32/value:int
23288     68/push 1/imm32/is-atom?:true
23289     68/push 0x11/imm32/alloc-id:fake:payload
23290     89/<- %ecx 4/r32/esp
23291 $test-compare-reg-with-mem:initialize-var1:
23292     # var var1/ecx: (payload var)
23293     68/push 0/imm32/register
23294     68/push 0/imm32/register
23295     68/push 0/imm32/no-stack-offset
23296     68/push 1/imm32/block-depth
23297     51/push-ecx
23298     68/push 0x11/imm32/alloc-id:fake
23299     68/push 0/imm32/name
23300     68/push 0/imm32/name
23301     68/push 0x11/imm32/alloc-id:fake:payload
23302     89/<- %ecx 4/r32/esp
23303 $test-compare-reg-with-mem:initialize-var1-name:
23304     # var1->name = "var1"
23305     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23306     (copy-array Heap "var1" %eax)
23307 $test-compare-reg-with-mem:initialize-var1-register:
23308     # var1->register = "eax"
23309     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
23310     (copy-array Heap "eax" %eax)
23311 $test-compare-reg-with-mem:initialize-var2:
23312     # var var2/edx: (payload var)
23313     68/push 0/imm32/register
23314     68/push 0/imm32/register
23315     68/push 8/imm32/stack-offset
23316     68/push 1/imm32/block-depth
23317     ff 6/subop/push *(ecx+0x10)
23318     68/push 0x11/imm32/alloc-id:fake
23319     68/push 0/imm32/name
23320     68/push 0/imm32/name
23321     68/push 0x11/imm32/alloc-id:fake:payload
23322     89/<- %edx 4/r32/esp
23323 $test-compare-reg-with-mem:initialize-var2-name:
23324     # var2->name = "var2"
23325     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
23326     (copy-array Heap "var2" %eax)
23327 $test-compare-reg-with-mem:initialize-inouts:
23328     # var inouts/esi: (payload stmt-var) = [var2]
23329     68/push 0/imm32/is-deref:false
23330     68/push 0/imm32/next
23331     68/push 0/imm32/next
23332     52/push-edx/var2
23333     68/push 0x11/imm32/alloc-id:fake
23334     68/push 0x11/imm32/alloc-id:fake:payload
23335     89/<- %esi 4/r32/esp
23336     # inouts = [var1, var2]
23337     68/push 0/imm32/is-deref:false
23338     56/push-esi/next
23339     68/push 0x11/imm32/alloc-id:fake
23340     51/push-ecx/var1
23341     68/push 0x11/imm32/alloc-id:fake
23342     68/push 0x11/imm32/alloc-id:fake:payload
23343     89/<- %esi 4/r32/esp
23344 $test-compare-reg-with-mem:initialize-stmt:
23345     # var stmt/esi: (addr statement)
23346     68/push 0/imm32/next
23347     68/push 0/imm32/next
23348     68/push 0/imm32/outputs
23349     68/push 0/imm32/outputs
23350     56/push-esi/inouts
23351     68/push 0x11/imm32/alloc-id:fake
23352     68/push 0/imm32/operation
23353     68/push 0/imm32/operation
23354     68/push 1/imm32/tag:stmt1
23355     89/<- %esi 4/r32/esp
23356 $test-compare-reg-with-mem:initialize-stmt-operation:
23357     # stmt->operation = "compare"
23358     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23359     (copy-array Heap "compare" %eax)
23360     # convert
23361     c7 0/subop/copy *Curr-block-depth 0/imm32
23362     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
23363     (flush _test-output-buffered-file)
23364 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
23370     # check output
23371     (check-next-stream-line-equal _test-output-stream "3b/compare<- *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-reg-with-mem")
23372     # . epilogue
23373     89/<- %esp 5/r32/ebp
23374     5d/pop-to-ebp
23375     c3/return
23376 
23377 test-compare-mem-with-literal:
23378     #   compare var1, 0x34
23379     # =>
23380     #   81 7/subop/compare *(ebp+___) 0x34/imm32
23381     #
23382     # . prologue
23383     55/push-ebp
23384     89/<- %ebp 4/r32/esp
23385     # setup
23386     (clear-stream _test-output-stream)
23387     (clear-stream $_test-output-buffered-file->buffer)
23388 $test-compare-mem-with-literal:initialize-type:
23389     # var type/ecx: (payload type-tree) = int
23390     68/push 0/imm32/right:null
23391     68/push 0/imm32/right:null
23392     68/push 0/imm32/left:unused
23393     68/push 1/imm32/value:int
23394     68/push 1/imm32/is-atom?:true
23395     68/push 0x11/imm32/alloc-id:fake:payload
23396     89/<- %ecx 4/r32/esp
23397 $test-compare-mem-with-literal:initialize-var1:
23398     # var var1/ecx: (payload var)
23399     68/push 0/imm32/register
23400     68/push 0/imm32/register
23401     68/push 8/imm32/stack-offset
23402     68/push 1/imm32/block-depth
23403     51/push-ecx
23404     68/push 0x11/imm32/alloc-id:fake
23405     68/push 0/imm32/name
23406     68/push 0/imm32/name
23407     68/push 0x11/imm32/alloc-id:fake:payload
23408     89/<- %ecx 4/r32/esp
23409 $test-compare-mem-with-literal:initialize-var1-name:
23410     # var1->name = "var1"
23411     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23412     (copy-array Heap "var1" %eax)
23413 $test-compare-mem-with-literal:initialize-literal-type:
23414     # var type/edx: (payload type-tree) = literal
23415     68/push 0/imm32/right:null
23416     68/push 0/imm32/right:null
23417     68/push 0/imm32/left:unused
23418     68/push 0/imm32/value:literal
23419     68/push 1/imm32/is-atom?:true
23420     68/push 0x11/imm32/alloc-id:fake:payload
23421     89/<- %edx 4/r32/esp
23422 $test-compare-mem-with-literal:initialize-literal:
23423     # var l/edx: (payload var)
23424     68/push 0/imm32/register
23425     68/push 0/imm32/register
23426     68/push 0/imm32/no-stack-offset
23427     68/push 1/imm32/block-depth
23428     52/push-edx
23429     68/push 0x11/imm32/alloc-id:fake
23430     68/push 0/imm32/name
23431     68/push 0/imm32/name
23432     68/push 0x11/imm32/alloc-id:fake:payload
23433     89/<- %edx 4/r32/esp
23434 $test-compare-mem-with-literal:initialize-literal-value:
23435     # l->name = "0x34"
23436     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
23437     (copy-array Heap "0x34" %eax)
23438 $test-compare-mem-with-literal:initialize-inouts:
23439     # var inouts/esi: (payload stmt-var) = [l]
23440     68/push 0/imm32/is-deref:false
23441     68/push 0/imm32/next
23442     68/push 0/imm32/next
23443     52/push-edx/l
23444     68/push 0x11/imm32/alloc-id:fake
23445     68/push 0x11/imm32/alloc-id:fake:payload
23446     89/<- %esi 4/r32/esp
23447     # var inouts = (handle stmt-var) = [var1, var2]
23448     68/push 0/imm32/is-deref:false
23449     56/push-esi/next
23450     68/push 0x11/imm32/alloc-id:fake
23451     51/push-ecx/var1
23452     68/push 0x11/imm32/alloc-id:fake
23453     68/push 0x11/imm32/alloc-id:fake:payload
23454     89/<- %esi 4/r32/esp
23455 $test-compare-mem-with-literal:initialize-stmt:
23456     # var stmt/esi: (addr statement)
23457     68/push 0/imm32/next
23458     68/push 0/imm32/next
23459     68/push 0/imm32/outputs
23460     68/push 0/imm32/outputs
23461     56/push-esi/inouts
23462     68/push 0x11/imm32/alloc-id:fake
23463     68/push 0/imm32/operation
23464     68/push 0/imm32/operation
23465     68/push 1/imm32/tag:stmt1
23466     89/<- %esi 4/r32/esp
23467 $test-compare-mem-with-literal:initialize-stmt-operation:
23468     # stmt->operation = "compare"
23469     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23470     (copy-array Heap "compare" %eax)
23471     # convert
23472     c7 0/subop/copy *Curr-block-depth 0/imm32
23473     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
23474     (flush _test-output-buffered-file)
23475 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
23481     # check output
23482     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare *(ebp+0x00000008) 0x34/imm32" "F - test-compare-mem-with-literal")
23483     # . epilogue
23484     89/<- %esp 5/r32/ebp
23485     5d/pop-to-ebp
23486     c3/return
23487 
23488 test-compare-eax-with-literal:
23489     #   compare var1/eax 0x34
23490     # =>
23491     #   3d/compare-eax-with 0x34/imm32
23492     #
23493     # . prologue
23494     55/push-ebp
23495     89/<- %ebp 4/r32/esp
23496     # setup
23497     (clear-stream _test-output-stream)
23498     (clear-stream $_test-output-buffered-file->buffer)
23499 $test-compare-eax-with-literal:initialize-type:
23500     # var type/ecx: (payload type-tree) = int
23501     68/push 0/imm32/right:null
23502     68/push 0/imm32/right:null
23503     68/push 0/imm32/left:unused
23504     68/push 1/imm32/value:int
23505     68/push 1/imm32/is-atom?:true
23506     68/push 0x11/imm32/alloc-id:fake:payload
23507     89/<- %ecx 4/r32/esp
23508 $test-compare-eax-with-literal:initialize-var1:
23509     # var var1/ecx: (payload var)
23510     68/push 0/imm32/register
23511     68/push 0/imm32/register
23512     68/push 0/imm32/no-stack-offset
23513     68/push 1/imm32/block-depth
23514     51/push-ecx
23515     68/push 0x11/imm32/alloc-id:fake
23516     68/push 0/imm32/name
23517     68/push 0/imm32/name
23518     68/push 0x11/imm32/alloc-id:fake:payload
23519     89/<- %ecx 4/r32/esp
23520 $test-compare-eax-with-literal:initialize-var1-name:
23521     # var1->name = "var1"
23522     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23523     (copy-array Heap "var1" %eax)
23524 $test-compare-eax-with-literal:initialize-var1-register:
23525     # v->register = "eax"
23526     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
23527     (copy-array Heap "eax" %eax)
23528 $test-compare-eax-with-literal:initialize-literal-type:
23529     # var type/edx: (payload type-tree) = literal
23530     68/push 0/imm32/right:null
23531     68/push 0/imm32/right:null
23532     68/push 0/imm32/left:unused
23533     68/push 0/imm32/value:literal
23534     68/push 1/imm32/is-atom?:true
23535     68/push 0x11/imm32/alloc-id:fake:payload
23536     89/<- %edx 4/r32/esp
23537 $test-compare-eax-with-literal:initialize-literal:
23538     # var l/edx: (payload var)
23539     68/push 0/imm32/register
23540     68/push 0/imm32/register
23541     68/push 0/imm32/no-stack-offset
23542     68/push 1/imm32/block-depth
23543     52/push-edx
23544     68/push 0x11/imm32/alloc-id:fake
23545     68/push 0/imm32/name
23546     68/push 0/imm32/name
23547     68/push 0x11/imm32/alloc-id:fake:payload
23548     89/<- %edx 4/r32/esp
23549 $test-compare-eax-with-literal:initialize-literal-value:
23550     # l->name = "0x34"
23551     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
23552     (copy-array Heap "0x34" %eax)
23553 $test-compare-eax-with-literal:initialize-inouts:
23554     # var inouts/esi: (payload stmt-var) = [l]
23555     68/push 0/imm32/is-deref:false
23556     68/push 0/imm32/next
23557     68/push 0/imm32/next
23558     52/push-edx/l
23559     68/push 0x11/imm32/alloc-id:fake
23560     68/push 0x11/imm32/alloc-id:fake:payload
23561     89/<- %esi 4/r32/esp
23562     # var inouts = (handle stmt-var) = [var1, var2]
23563     68/push 0/imm32/is-deref:false
23564     56/push-esi/next
23565     68/push 0x11/imm32/alloc-id:fake
23566     51/push-ecx/var1
23567     68/push 0x11/imm32/alloc-id:fake
23568     68/push 0x11/imm32/alloc-id:fake:payload
23569     89/<- %esi 4/r32/esp
23570 $test-compare-eax-with-literal:initialize-stmt:
23571     # var stmt/esi: (addr statement)
23572     68/push 0/imm32/next
23573     68/push 0/imm32/next
23574     68/push 0/imm32/outputs
23575     68/push 0/imm32/outputs
23576     56/push-esi/inouts
23577     68/push 0x11/imm32/alloc-id:fake
23578     68/push 0/imm32/operation
23579     68/push 0/imm32/operation
23580     68/push 1/imm32/tag:stmt1
23581     89/<- %esi 4/r32/esp
23582 $test-compare-eax-with-literal:initialize-stmt-operation:
23583     # stmt->operation = "compare"
23584     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23585     (copy-array Heap "compare" %eax)
23586     # convert
23587     c7 0/subop/copy *Curr-block-depth 0/imm32
23588     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
23589     (flush _test-output-buffered-file)
23590 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
23596     # check output
23597     (check-next-stream-line-equal _test-output-stream "3d/compare-eax-with 0x34/imm32" "F - test-compare-eax-with-literal")
23598     # . epilogue
23599     89/<- %esp 5/r32/ebp
23600     5d/pop-to-ebp
23601     c3/return
23602 
23603 test-compare-reg-with-literal:
23604     #   compare var1/ecx 0x34
23605     # =>
23606     #   81 7/subop/compare %ecx 0x34/imm32
23607     #
23608     # . prologue
23609     55/push-ebp
23610     89/<- %ebp 4/r32/esp
23611     # setup
23612     (clear-stream _test-output-stream)
23613     (clear-stream $_test-output-buffered-file->buffer)
23614 $test-compare-reg-with-literal:initialize-type:
23615     # var type/ecx: (payload type-tree) = int
23616     68/push 0/imm32/right:null
23617     68/push 0/imm32/right:null
23618     68/push 0/imm32/left:unused
23619     68/push 1/imm32/value:int
23620     68/push 1/imm32/is-atom?:true
23621     68/push 0x11/imm32/alloc-id:fake:payload
23622     89/<- %ecx 4/r32/esp
23623 $test-compare-reg-with-literal:initialize-var1:
23624     # var var1/ecx: (payload var)
23625     68/push 0/imm32/register
23626     68/push 0/imm32/register
23627     68/push 0/imm32/no-stack-offset
23628     68/push 1/imm32/block-depth
23629     51/push-ecx
23630     68/push 0x11/imm32/alloc-id:fake
23631     68/push 0/imm32/name
23632     68/push 0/imm32/name
23633     68/push 0x11/imm32/alloc-id:fake:payload
23634     89/<- %ecx 4/r32/esp
23635 $test-compare-reg-with-literal:initialize-var1-name:
23636     # var1->name = "var1"
23637     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23638     (copy-array Heap "var1" %eax)
23639 $test-compare-reg-with-literal:initialize-var1-register:
23640     # v->register = "ecx"
23641     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
23642     (copy-array Heap "ecx" %eax)
23643 $test-compare-reg-with-literal:initialize-literal-type:
23644     # var type/edx: (payload type-tree) = literal
23645     68/push 0/imm32/right:null
23646     68/push 0/imm32/right:null
23647     68/push 0/imm32/left:unused
23648     68/push 0/imm32/value:literal
23649     68/push 1/imm32/is-atom?:true
23650     68/push 0x11/imm32/alloc-id:fake:payload
23651     89/<- %edx 4/r32/esp
23652 $test-compare-reg-with-literal:initialize-literal:
23653     # var l/edx: (payload var)
23654     68/push 0/imm32/register
23655     68/push 0/imm32/register
23656     68/push 0/imm32/no-stack-offset
23657     68/push 1/imm32/block-depth
23658     52/push-edx
23659     68/push 0x11/imm32/alloc-id:fake
23660     68/push 0/imm32/name
23661     68/push 0/imm32/name
23662     68/push 0x11/imm32/alloc-id:fake:payload
23663     89/<- %edx 4/r32/esp
23664 $test-compare-reg-with-literal:initialize-literal-value:
23665     # l->name = "0x34"
23666     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
23667     (copy-array Heap "0x34" %eax)
23668 $test-compare-reg-with-literal:initialize-inouts:
23669     # var inouts/esi: (payload stmt-var) = [l]
23670     68/push 0/imm32/is-deref:false
23671     68/push 0/imm32/next
23672     68/push 0/imm32/next
23673     52/push-edx/l
23674     68/push 0x11/imm32/alloc-id:fake
23675     68/push 0x11/imm32/alloc-id:fake:payload
23676     89/<- %esi 4/r32/esp
23677     # var inouts = (handle stmt-var) = [var1, var2]
23678     68/push 0/imm32/is-deref:false
23679     56/push-esi/next
23680     68/push 0x11/imm32/alloc-id:fake
23681     51/push-ecx/var1
23682     68/push 0x11/imm32/alloc-id:fake
23683     68/push 0x11/imm32/alloc-id:fake:payload
23684     89/<- %esi 4/r32/esp
23685 $test-compare-reg-with-literal:initialize-stmt:
23686     # var stmt/esi: (addr statement)
23687     68/push 0/imm32/next
23688     68/push 0/imm32/next
23689     68/push 0/imm32/outputs
23690     68/push 0/imm32/outputs
23691     56/push-esi/inouts
23692     68/push 0x11/imm32/alloc-id:fake
23693     68/push 0/imm32/operation
23694     68/push 0/imm32/operation
23695     68/push 1/imm32/tag:stmt1
23696     89/<- %esi 4/r32/esp
23697 $test-compare-reg-with-literal:initialize-stmt-operation:
23698     # stmt->operation = "compare"
23699     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23700     (copy-array Heap "compare" %eax)
23701     # convert
23702     c7 0/subop/copy *Curr-block-depth 0/imm32
23703     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
23704     (flush _test-output-buffered-file)
23705 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
23711     # check output
23712     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare %ecx 0x34/imm32" "F - test-compare-reg-with-literal")
23713     # . epilogue
23714     89/<- %esp 5/r32/ebp
23715     5d/pop-to-ebp
23716     c3/return
23717 
23718 test-emit-subx-stmt-function-call:
23719     # Call a function on a variable on the stack.
23720     #   f foo
23721     # =>
23722     #   (f *(ebp-8))
23723     # (Changing the function name supports overloading in general, but here it
23724     # just serves to help disambiguate things.)
23725     #
23726     # There's a variable on the var stack as follows:
23727     #   name: 'foo'
23728     #   type: int
23729     #   stack-offset: -8
23730     #
23731     # There's nothing in primitives.
23732     #
23733     # We don't perform any checking here on the type of 'f'.
23734     #
23735     # . prologue
23736     55/push-ebp
23737     89/<- %ebp 4/r32/esp
23738     # setup
23739     (clear-stream _test-output-stream)
23740     (clear-stream $_test-output-buffered-file->buffer)
23741 $test-emit-subx-function-call:initialize-type:
23742     # var type/ecx: (payload type-tree) = int
23743     68/push 0/imm32/right:null
23744     68/push 0/imm32/right:null
23745     68/push 0/imm32/left:unused
23746     68/push 1/imm32/value:int
23747     68/push 1/imm32/is-atom?:true
23748     68/push 0x11/imm32/alloc-id:fake:payload
23749     89/<- %ecx 4/r32/esp
23750 $test-emit-subx-function-call:initialize-var:
23751     # var var-foo/ecx: (payload var) = var(type)
23752     68/push 0/imm32/no-register
23753     68/push 0/imm32/no-register
23754     68/push -8/imm32/stack-offset
23755     68/push 1/imm32/block-depth
23756     51/push-ecx/type
23757     68/push 0x11/imm32/alloc-id:fake
23758     68/push 0/imm32/name
23759     68/push 0/imm32/name
23760     68/push 0x11/imm32/alloc-id:fake:payload
23761     89/<- %ecx 4/r32/esp
23762 $test-emit-subx-function-call:initialize-var-name:
23763     # var-foo->name = "foo"
23764     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23765     (copy-array Heap "foo" %eax)
23766 $test-emit-subx-function-call:initialize-stmt-var:
23767     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
23768     68/push 0/imm32/is-deref:false
23769     68/push 0/imm32/next
23770     68/push 0/imm32/next
23771     51/push-ecx/var-foo
23772     68/push 0x11/imm32/alloc-id:fake
23773     68/push 0x11/imm32/alloc-id:fake:payload
23774     89/<- %ebx 4/r32/esp
23775 $test-emit-subx-function-call:initialize-stmt:
23776     # var stmt/esi: (addr statement)
23777     68/push 0/imm32/no-outputs
23778     68/push 0/imm32/no-outputs
23779     53/push-ebx/inouts
23780     68/push 0x11/imm32/alloc-id:fake
23781     68/push 0/imm32/operation
23782     68/push 0/imm32/operation
23783     68/push 1/imm32/tag
23784     89/<- %esi 4/r32/esp
23785 $test-emit-subx-function-call:initialize-stmt-operation:
23786     # stmt->operation = "f"
23787     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23788     (copy-array Heap "f" %eax)
23789     # convert
23790     c7 0/subop/copy *Curr-block-depth 0/imm32
23791     (emit-subx-stmt _test-output-buffered-file %esi 0 Stderr 0)
23792     (flush _test-output-buffered-file)
23793 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
23799     # check output
23800     (check-next-stream-line-equal _test-output-stream "(f *(ebp+0xfffffff8))" "F - test-emit-subx-stmt-function-call")
23801     # . epilogue
23802     89/<- %esp 5/r32/ebp
23803     5d/pop-to-ebp
23804     c3/return
23805 
23806 test-emit-subx-stmt-function-call-with-literal-arg:
23807     # Call a function on a literal.
23808     #   f 0x34
23809     # =>
23810     #   (f2 0x34)
23811     #
23812     # . prologue
23813     55/push-ebp
23814     89/<- %ebp 4/r32/esp
23815     # setup
23816     (clear-stream _test-output-stream)
23817     (clear-stream $_test-output-buffered-file->buffer)
23818 $test-emit-subx-function-call-with-literal-arg:initialize-type:
23819     # var type/ecx: (payload type-tree) = int
23820     68/push 0/imm32/right:null
23821     68/push 0/imm32/right:null
23822     68/push 0/imm32/left:unused
23823     68/push 0/imm32/value:literal
23824     68/push 1/imm32/is-atom?:true
23825     68/push 0x11/imm32/alloc-id:fake:payload
23826     89/<- %ecx 4/r32/esp
23827 $test-emit-subx-function-call-with-literal-arg:initialize-var:
23828     # var var-foo/ecx: (payload var) = var(lit)
23829     68/push 0/imm32/no-register
23830     68/push 0/imm32/no-register
23831     68/push 0/imm32/no-stack-offset
23832     68/push 1/imm32/block-depth
23833     51/push-ecx/type
23834     68/push 0x11/imm32/alloc-id:fake
23835     68/push 0/imm32/name
23836     68/push 0/imm32/name
23837     68/push 0x11/imm32/alloc-id:fake:payload
23838     89/<- %ecx 4/r32/esp
23839 $test-emit-subx-function-call-with-literal-arg:initialize-var-name:
23840     # var-foo->name = "0x34"
23841     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23842     (copy-array Heap "0x34" %eax)
23843 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-var:
23844     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
23845     68/push 0/imm32/is-deref:false
23846     68/push 0/imm32/next
23847     68/push 0/imm32/next
23848     51/push-ecx/var-foo
23849     68/push 0x11/imm32/alloc-id:fake
23850     68/push 0x11/imm32/alloc-id:fake:payload
23851     89/<- %ebx 4/r32/esp
23852 $test-emit-subx-function-call-with-literal-arg:initialize-stmt:
23853     # var stmt/esi: (addr statement)
23854     68/push 0/imm32/no-outputs
23855     68/push 0/imm32/no-outputs
23856     53/push-ebx/inouts
23857     68/push 0x11/imm32/alloc-id:fake
23858     68/push 0/imm32/operation
23859     68/push 0/imm32/operation
23860     68/push 1/imm32/tag
23861     89/<- %esi 4/r32/esp
23862 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-operation:
23863     # stmt->operation = "f"
23864     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23865     (copy-array Heap "f" %eax)
23866     # convert
23867     c7 0/subop/copy *Curr-block-depth 0/imm32
23868     (emit-subx-stmt _test-output-buffered-file %esi 0 %ebx Stderr 0)
23869     (flush _test-output-buffered-file)
23870 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
23876     # check output
23877     (check-next-stream-line-equal _test-output-stream "(f 0x34)" "F - test-emit-subx-stmt-function-call-with-literal-arg")
23878     # . epilogue
23879     89/<- %esp 5/r32/ebp
23880     5d/pop-to-ebp
23881     c3/return
23882 
23883 emit-indent:  # out: (addr buffered-file), n: int
23884     # . prologue
23885     55/push-ebp
23886     89/<- %ebp 4/r32/esp
23887     # . save registers
23888     50/push-eax
23889     # var i/eax: int = n
23890     8b/-> *(ebp+0xc) 0/r32/eax
23891     {
23892       # if (i <= 0) break
23893       3d/compare-eax-with 0/imm32
23894       7e/jump-if-<= break/disp8
23895       (write-buffered *(ebp+8) "  ")
23896       48/decrement-eax
23897       eb/jump loop/disp8
23898     }
23899 $emit-indent:end:
23900     # . restore registers
23901     58/pop-to-eax
23902     # . epilogue
23903     89/<- %esp 5/r32/ebp
23904     5d/pop-to-ebp
23905     c3/return
23906 
23907 emit-subx-prologue:  # out: (addr buffered-file)
23908     # . prologue
23909     55/push-ebp
23910     89/<- %ebp 4/r32/esp
23911     #
23912     (write-buffered *(ebp+8) "  # . prologue\n")
23913     (write-buffered *(ebp+8) "  55/push-ebp\n")
23914     (write-buffered *(ebp+8) "  89/<- %ebp 4/r32/esp\n")
23915 $emit-subx-prologue:end:
23916     # . epilogue
23917     89/<- %esp 5/r32/ebp
23918     5d/pop-to-ebp
23919     c3/return
23920 
23921 emit-subx-epilogue:  # out: (addr buffered-file)
23922     # . prologue
23923     55/push-ebp
23924     89/<- %ebp 4/r32/esp
23925     #
23926     (write-buffered *(ebp+8) "  # . epilogue\n")
23927     (write-buffered *(ebp+8) "  89/<- %esp 5/r32/ebp\n")
23928     (write-buffered *(ebp+8) "  5d/pop-to-ebp\n")
23929     (write-buffered *(ebp+8) "  c3/return\n")
23930 $emit-subx-epilogue:end:
23931     # . epilogue
23932     89/<- %esp 5/r32/ebp
23933     5d/pop-to-ebp
23934     c3/return