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.md 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) || c == '-') return new var(name)
10350     {
10351       81 7/subop/compare %ecx 0x2d/imm32/dash
10352       74/jump-if-= $lookup-var-or-literal:literal/disp8
10353       (is-decimal-digit? %ecx)  # => eax
10354       3d/compare-eax-and 0/imm32/false
10355       74/jump-if-= break/disp8
10356 $lookup-var-or-literal:literal:
10357       (new-literal-integer Heap %esi *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
10358       eb/jump $lookup-var-or-literal:end/disp8
10359     }
10360     # else if (c == '"') return new var(name)
10361     {
10362       81 7/subop/compare %ecx 0x22/imm32/dquote
10363       75/jump-if-!= break/disp8
10364 $lookup-var-or-literal:literal-string:
10365       (new-literal Heap %esi *(ebp+0x10))
10366       eb/jump $lookup-var-or-literal:end/disp8
10367     }
10368     # otherwise return lookup-var(name, vars)
10369     {
10370 $lookup-var-or-literal:var:
10371       (lookup-var %esi *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
10372     }
10373 $lookup-var-or-literal:end:
10374     # . restore registers
10375     5e/pop-to-esi
10376     59/pop-to-ecx
10377     58/pop-to-eax
10378     # . epilogue
10379     89/<- %esp 5/r32/ebp
10380     5d/pop-to-ebp
10381     c3/return
10382 
10383 $lookup-var-or-literal:abort:
10384     (write-buffered *(ebp+0x18) "fn ")
10385     8b/-> *(ebp+0x14) 0/r32/eax
10386     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10387     (write-buffered *(ebp+0x18) %eax)
10388     (write-buffered *(ebp+0x18) ": empty variable!")
10389     (flush *(ebp+0x18))
10390     (stop *(ebp+0x1c) 1)
10391     # never gets here
10392 
10393 # return first 'name' from the top (back) of 'vars' and abort if not found
10394 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)
10395     # . prologue
10396     55/push-ebp
10397     89/<- %ebp 4/r32/esp
10398     # . save registers
10399     50/push-eax
10400     #
10401     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
10402     # if (*out == 0) abort
10403     8b/-> *(ebp+0x10) 0/r32/eax
10404     81 7/subop/compare *eax 0/imm32
10405     74/jump-if-= $lookup-var:abort/disp8
10406 $lookup-var:end:
10407     # . restore registers
10408     58/pop-to-eax
10409     # . epilogue
10410     89/<- %esp 5/r32/ebp
10411     5d/pop-to-ebp
10412     c3/return
10413 
10414 $lookup-var:abort:
10415     (write-buffered *(ebp+0x18) "fn ")
10416     8b/-> *(ebp+0x14) 0/r32/eax
10417     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10418     (write-buffered *(ebp+0x18) %eax)
10419     (write-buffered *(ebp+0x18) ": unknown variable '")
10420     (write-slice-buffered *(ebp+0x18) *(ebp+8))
10421     (write-buffered *(ebp+0x18) "'\n")
10422     (flush *(ebp+0x18))
10423     (stop *(ebp+0x1c) 1)
10424     # never gets here
10425 
10426 # return first 'name' from the top (back) of 'vars', and 0/null if not found
10427 # ensure that 'name' if in a register is the topmost variable in that register
10428 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)
10429     # pseudocode:
10430     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
10431     #   var min = vars->data
10432     #   while curr >= min
10433     #     var v: (handle var) = *curr
10434     #     if v->name == name
10435     #       return
10436     #     curr -= 12
10437     #
10438     # . prologue
10439     55/push-ebp
10440     89/<- %ebp 4/r32/esp
10441     # . save registers
10442     50/push-eax
10443     51/push-ecx
10444     52/push-edx
10445     53/push-ebx
10446     56/push-esi
10447     57/push-edi
10448     # clear out
10449     (zero-out *(ebp+0x10) *Handle-size)
10450     # esi = vars
10451     8b/-> *(ebp+0xc) 6/r32/esi
10452     # ebx = vars->top
10453     8b/-> *esi 3/r32/ebx
10454     # if (vars->top > vars->size) abort
10455     3b/compare<- *(esi+4) 0/r32/eax
10456     0f 8f/jump-if-> $lookup-var-helper:error1/disp32
10457     # var min/edx: (addr handle var) = vars->data
10458     8d/copy-address *(esi+8) 2/r32/edx
10459     # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
10460     8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
10461     # var var-in-reg/edi: 8 addrs
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     68/push 0/imm32
10469     68/push 0/imm32
10470     89/<- %edi 4/r32/esp
10471     {
10472 $lookup-var-helper:loop:
10473       # if (curr < min) return
10474       39/compare %ebx 2/r32/edx
10475       0f 82/jump-if-addr< break/disp32
10476       # var v/ecx: (addr var) = lookup(*curr)
10477       (lookup *ebx *(ebx+4))  # => eax
10478       89/<- %ecx 0/r32/eax
10479       # var vn/eax: (addr array byte) = lookup(v->name)
10480       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
10481       # if (vn == name) return curr
10482       (slice-equal? *(ebp+8) %eax)  # => eax
10483       3d/compare-eax-and 0/imm32/false
10484       {
10485         74/jump-if-= break/disp8
10486 $lookup-var-helper:found:
10487         # var vr/eax: (addr array byte) = lookup(v->register)
10488         (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
10489         3d/compare-eax-and 0/imm32
10490         {
10491           74/jump-if-= break/disp8
10492 $lookup-var-helper:found-register:
10493           # var reg/eax: int = get(Registers, vr)
10494           (get Mu-registers %eax 0xc "Mu-registers")  # => eax
10495           8b/-> *eax 0/r32/eax
10496           # if (var-in-reg[reg]) error
10497           8b/-> *(edi+eax<<2) 0/r32/eax
10498           3d/compare-eax-and 0/imm32
10499           0f 85/jump-if-!= $lookup-var-helper:error2/disp32
10500         }
10501 $lookup-var-helper:return:
10502         # esi = out
10503         8b/-> *(ebp+0x10) 6/r32/esi
10504         # *out = *curr
10505         8b/-> *ebx 0/r32/eax
10506         89/<- *esi 0/r32/eax
10507         8b/-> *(ebx+4) 0/r32/eax
10508         89/<- *(esi+4) 0/r32/eax
10509         # return
10510         eb/jump $lookup-var-helper:end/disp8
10511       }
10512       # 'name' not yet found; update var-in-reg if v in register
10513       # . var vr/eax: (addr array byte) = lookup(v->register)
10514       (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
10515       # . if (var == 0) continue
10516       3d/compare-eax-and 0/imm32
10517       74/jump-if-= $lookup-var-helper:continue/disp8
10518       # . var reg/eax: int = get(Registers, vr)
10519       (get Mu-registers %eax 0xc "Mu-registers")  # => eax
10520       8b/-> *eax 0/r32/eax
10521       # . if (var-in-reg[reg] == 0) var-in-reg[reg] = v
10522       81 7/subop/compare *(edi+eax<<2) 0/imm32
10523       75/jump-if-!= $lookup-var-helper:continue/disp8
10524       89/<- *(edi+eax<<2) 1/r32/ecx
10525 $lookup-var-helper:continue:
10526       # curr -= 12
10527       81 5/subop/subtract %ebx 0xc/imm32
10528       e9/jump loop/disp32
10529     }
10530 $lookup-var-helper:end:
10531     # . reclaim locals
10532     81 0/subop/add %esp 0x20/imm32
10533     # . restore registers
10534     5f/pop-to-edi
10535     5e/pop-to-esi
10536     5b/pop-to-ebx
10537     5a/pop-to-edx
10538     59/pop-to-ecx
10539     58/pop-to-eax
10540     # . epilogue
10541     89/<- %esp 5/r32/ebp
10542     5d/pop-to-ebp
10543     c3/return
10544 
10545 $lookup-var-helper:error1:
10546     (write-buffered *(ebp+0x18) "fn ")
10547     8b/-> *(ebp+0x14) 0/r32/eax
10548     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10549     (write-buffered *(ebp+0x18) %eax)
10550     (write-buffered *(ebp+0x18) ": malformed stack when looking up '")
10551     (write-slice-buffered *(ebp+0x18) *(ebp+8))
10552     (write-buffered *(ebp+0x18) "'\n")
10553     (flush *(ebp+0x18))
10554     (stop *(ebp+0x1c) 1)
10555     # never gets here
10556 
10557 $lookup-var-helper:error2:
10558     # eax contains the conflicting var at this point
10559     (write-buffered *(ebp+0x18) "fn ")
10560     50/push-eax
10561     8b/-> *(ebp+0x14) 0/r32/eax
10562     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10563     (write-buffered *(ebp+0x18) %eax)
10564     58/pop-eax
10565     (write-buffered *(ebp+0x18) ": register ")
10566     50/push-eax
10567     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
10568     (write-buffered *(ebp+0x18) %eax)
10569     58/pop-to-eax
10570     (write-buffered *(ebp+0x18) " reads var '")
10571     (write-slice-buffered *(ebp+0x18) *(ebp+8))
10572     (write-buffered *(ebp+0x18) "' after writing var '")
10573     (lookup *eax *(eax+4))  # Var-name Var-name => eax
10574     (write-buffered *(ebp+0x18) %eax)
10575     (write-buffered *(ebp+0x18) "'\n")
10576     (flush *(ebp+0x18))
10577     (stop *(ebp+0x1c) 1)
10578     # never gets here
10579 
10580 dump-vars:  # vars: (addr stack live-var)
10581     # pseudocode:
10582     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
10583     #   var min = vars->data
10584     #   while curr >= min
10585     #     var v: (handle var) = *curr
10586     #     print v
10587     #     curr -= 12
10588     #
10589     # . prologue
10590     55/push-ebp
10591     89/<- %ebp 4/r32/esp
10592     # . save registers
10593     52/push-edx
10594     53/push-ebx
10595     56/push-esi
10596     # esi = vars
10597     8b/-> *(ebp+8) 6/r32/esi
10598     # ebx = vars->top
10599     8b/-> *esi 3/r32/ebx
10600     # var min/edx: (addr handle var) = vars->data
10601     8d/copy-address *(esi+8) 2/r32/edx
10602     # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
10603     8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
10604     {
10605 $dump-vars:loop:
10606       # if (curr < min) return
10607       39/compare %ebx 2/r32/edx
10608       0f 82/jump-if-addr< break/disp32
10609       #
10610       (write-buffered Stderr "  var@")
10611       (dump-var 2 %ebx)
10612       # curr -= 12
10613       81 5/subop/subtract %ebx 0xc/imm32
10614       e9/jump loop/disp32
10615     }
10616 $dump-vars:end:
10617     # . restore registers
10618     5e/pop-to-esi
10619     5b/pop-to-ebx
10620     5a/pop-to-edx
10621     # . epilogue
10622     89/<- %esp 5/r32/ebp
10623     5d/pop-to-ebp
10624     c3/return
10625 
10626 == data
10627 # Like Registers, but no esp or ebp
10628 Mu-registers:  # (addr stream {(handle array byte), int})
10629   # a table is a stream
10630   0x48/imm32/write
10631   0/imm32/read
10632   0x48/imm32/length
10633   # data
10634   # it is perfectly ok to use fake alloc-ids -- as long as you never try to reclaim them
10635   0x11/imm32/alloc-id $Mu-register-eax/imm32 0/imm32
10636   0x11/imm32/alloc-id $Mu-register-ecx/imm32 1/imm32
10637   0x11/imm32/alloc-id $Mu-register-edx/imm32 2/imm32
10638   0x11/imm32/alloc-id $Mu-register-ebx/imm32 3/imm32
10639   0x11/imm32/alloc-id $Mu-register-esi/imm32 6/imm32
10640   0x11/imm32/alloc-id $Mu-register-edi/imm32 7/imm32
10641 
10642 $Mu-register-eax:
10643   0x11/imm32/alloc-id
10644   3/imm32/size
10645   0x65/e 0x61/a 0x78/x
10646 
10647 $Mu-register-ecx:
10648   0x11/imm32/alloc-id
10649   3/imm32/size
10650   0x65/e 0x63/c 0x78/x
10651 
10652 $Mu-register-edx:
10653   0x11/imm32/alloc-id
10654   3/imm32/size
10655   0x65/e 0x64/d 0x78/x
10656 
10657 $Mu-register-ebx:
10658   0x11/imm32/alloc-id
10659   3/imm32/size
10660   0x65/e 0x62/b 0x78/x
10661 
10662 $Mu-register-esi:
10663   0x11/imm32/alloc-id
10664   3/imm32/size
10665   0x65/e 0x73/s 0x69/i
10666 
10667 $Mu-register-edi:
10668   0x11/imm32/alloc-id
10669   3/imm32/size
10670   0x65/e 0x64/d 0x69/i
10671 
10672 == code
10673 
10674 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found
10675 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)
10676     # . prologue
10677     55/push-ebp
10678     89/<- %ebp 4/r32/esp
10679     # . save registers
10680     50/push-eax
10681     #
10682     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))  # arg order slightly different; 'fn' is deemphasized
10683     {
10684       # if (out != 0) return
10685       8b/-> *(ebp+0x14) 0/r32/eax
10686       81 7/subop/compare *eax 0/imm32
10687       75/jump-if-!= break/disp8
10688       # if name is one of fn's outputs, return it
10689       (find-in-function-outputs *(ebp+0x10) *(ebp+8) *(ebp+0x14))
10690       8b/-> *(ebp+0x14) 0/r32/eax
10691       81 7/subop/compare *eax 0/imm32
10692       # otherwise abort
10693       0f 84/jump-if-= $lookup-or-define-var:abort/disp32
10694     }
10695 $lookup-or-define-var:end:
10696     # . restore registers
10697     58/pop-to-eax
10698     # . epilogue
10699     89/<- %esp 5/r32/ebp
10700     5d/pop-to-ebp
10701     c3/return
10702 
10703 $lookup-or-define-var:abort:
10704     (write-buffered *(ebp+0x18) "unknown variable '")
10705     (write-slice-buffered *(ebp+0x18) *(ebp+8))
10706     (write-buffered *(ebp+0x18) "'\n")
10707     (flush *(ebp+0x18))
10708     (stop *(ebp+0x1c) 1)
10709     # never gets here
10710 
10711 find-in-function-outputs:  # fn: (addr function), name: (addr slice), out: (addr handle var)
10712     # . prologue
10713     55/push-ebp
10714     89/<- %ebp 4/r32/esp
10715     # . save registers
10716     50/push-eax
10717     51/push-ecx
10718     # var curr/ecx: (addr list var) = lookup(fn->outputs)
10719     8b/-> *(ebp+8) 1/r32/ecx
10720     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
10721     89/<- %ecx 0/r32/eax
10722     # while curr != null
10723     {
10724       81 7/subop/compare %ecx 0/imm32
10725       74/jump-if-= break/disp8
10726       # var v/eax: (addr var) = lookup(curr->value)
10727       (lookup *ecx *(ecx+4))  # List-value List-value => eax
10728       # var s/eax: (addr array byte) = lookup(v->name)
10729       (lookup *eax *(eax+4))  # Var-name Var-name => eax
10730       # if (s == name) return curr->value
10731       (slice-equal? *(ebp+0xc) %eax)  # => eax
10732       3d/compare-eax-and 0/imm32/false
10733       {
10734         74/jump-if-= break/disp8
10735         # var edi = out
10736         57/push-edi
10737         8b/-> *(ebp+0x10) 7/r32/edi
10738         # *out = curr->value
10739         8b/-> *ecx 0/r32/eax
10740         89/<- *edi 0/r32/eax
10741         8b/-> *(ecx+4) 0/r32/eax
10742         89/<- *(edi+4) 0/r32/eax
10743         #
10744         5f/pop-to-edi
10745         eb/jump $find-in-function-outputs:end/disp8
10746       }
10747       # curr = curr->next
10748       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
10749       89/<- %ecx 0/r32/eax
10750       #
10751       eb/jump loop/disp8
10752     }
10753     b8/copy-to-eax 0/imm32
10754 $find-in-function-outputs:end:
10755     # . restore registers
10756     59/pop-to-ecx
10757     58/pop-to-eax
10758     # . epilogue
10759     89/<- %esp 5/r32/ebp
10760     5d/pop-to-ebp
10761     c3/return
10762 
10763 # push 'out' to 'vars' if not already there; it's assumed to be a fn output
10764 maybe-define-var:  # out: (handle var), vars: (addr stack live-var)
10765     # . prologue
10766     55/push-ebp
10767     89/<- %ebp 4/r32/esp
10768     # . save registers
10769     50/push-eax
10770     # var out-addr/eax: (addr var)
10771     (lookup *(ebp+8) *(ebp+0xc))  # => eax
10772     #
10773     (binding-exists? %eax *(ebp+0x10))  # => eax
10774     3d/compare-eax-and 0/imm32/false
10775     75/jump-if-!= $maybe-define-var:end/disp8
10776     # otherwise update vars
10777     (push *(ebp+0x10) *(ebp+8))
10778     (push *(ebp+0x10) *(ebp+0xc))
10779     (push *(ebp+0x10) 0)  # 'out' is always a fn output; never spill it
10780 $maybe-define-var:end:
10781     # . restore registers
10782     58/pop-to-eax
10783     # . epilogue
10784     89/<- %esp 5/r32/ebp
10785     5d/pop-to-ebp
10786     c3/return
10787 
10788 # simpler version of lookup-var-helper
10789 binding-exists?:  # target: (addr var), vars: (addr stack live-var) -> result/eax: boolean
10790     # pseudocode:
10791     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
10792     #   var min = vars->data
10793     #   while curr >= min
10794     #     var v: (handle var) = *curr
10795     #     if v->name == target->name
10796     #       return true
10797     #     curr -= 12
10798     #   return false
10799     #
10800     # . prologue
10801     55/push-ebp
10802     89/<- %ebp 4/r32/esp
10803     # . save registers
10804     51/push-ecx
10805     52/push-edx
10806     56/push-esi
10807     # var target-name/ecx: (addr array byte) = lookup(target->name)
10808     8b/-> *(ebp+8) 0/r32/eax
10809     (lookup *eax *(eax+4))  # Var-name Var-name => eax
10810     89/<- %ecx 0/r32/eax
10811     # esi = vars
10812     8b/-> *(ebp+0xc) 6/r32/esi
10813     # eax = vars->top
10814     8b/-> *esi 0/r32/eax
10815     # var min/edx: (addr handle var) = vars->data
10816     8d/copy-address *(esi+8) 2/r32/edx
10817     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
10818     8d/copy-address *(esi+eax-4) 6/r32/esi  # vars + 8 + vars->type - 12
10819     {
10820 $binding-exists?:loop:
10821       # if (curr < min) return
10822       39/compare %esi 2/r32/edx
10823       0f 82/jump-if-addr< break/disp32
10824       # var v/eax: (addr var) = lookup(*curr)
10825       (lookup *esi *(esi+4))  # => eax
10826       # var vn/eax: (addr array byte) = lookup(v->name)
10827       (lookup *eax *(eax+4))  # Var-name Var-name => eax
10828       # if (vn == target-name) return true
10829       (string-equal? %ecx %eax)  # => eax
10830       3d/compare-eax-and 0/imm32/false
10831       75/jump-if-!= $binding-exists?:end/disp8  # eax already contains true
10832       # curr -= 12
10833       81 5/subop/subtract %esi 0xc/imm32
10834       e9/jump loop/disp32
10835     }
10836     b8/copy-to-eax 0/imm32/false
10837 $binding-exists?:end:
10838     # . restore registers
10839     5e/pop-to-esi
10840     5a/pop-to-edx
10841     59/pop-to-ecx
10842     # . epilogue
10843     89/<- %esp 5/r32/ebp
10844     5d/pop-to-ebp
10845     c3/return
10846 
10847 test-parse-mu-stmt:
10848     # . prologue
10849     55/push-ebp
10850     89/<- %ebp 4/r32/esp
10851     # setup
10852     (clear-stream _test-input-stream)
10853     (write _test-input-stream "increment n\n")
10854     # var vars/ecx: (stack (addr var) 16)
10855     81 5/subop/subtract %esp 0xc0/imm32
10856     68/push 0xc0/imm32/size
10857     68/push 0/imm32/top
10858     89/<- %ecx 4/r32/esp
10859     (clear-stack %ecx)
10860     # var v/edx: (handle var)
10861     68/push 0/imm32
10862     68/push 0/imm32
10863     89/<- %edx 4/r32/esp
10864     # var s/eax: (handle array byte)
10865     68/push 0/imm32
10866     68/push 0/imm32
10867     89/<- %eax 4/r32/esp
10868     # v = new var("n")
10869     (copy-array Heap "n" %eax)
10870     (new-var Heap *eax *(eax+4) %edx)
10871     #
10872     (push %ecx *edx)
10873     (push %ecx *(edx+4))
10874     (push %ecx 0)
10875     # var out/eax: (handle stmt)
10876     68/push 0/imm32
10877     68/push 0/imm32
10878     89/<- %eax 4/r32/esp
10879     # convert
10880     (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
10881     # var out-addr/edx: (addr stmt) = lookup(*out)
10882     (lookup *eax *(eax+4))  # => eax
10883     89/<- %edx 0/r32/eax
10884     # out->tag
10885     (check-ints-equal *edx 1 "F - test-parse-mu-stmt/tag")  # Stmt-tag is Stmt1
10886     # out->operation
10887     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
10888     (check-strings-equal %eax "increment" "F - test-parse-mu-stmt/name")  # Stmt1-operation
10889     # out->inouts->value->name
10890     # . eax = out->inouts
10891     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
10892     # . eax = out->inouts->value
10893     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10894     # . eax = out->inouts->value->name
10895     (lookup *eax *(eax+4))  # Var-name Var-name => eax
10896     # .
10897     (check-strings-equal %eax "n" "F - test-parse-mu-stmt/inout:0")
10898     # . epilogue
10899     89/<- %esp 5/r32/ebp
10900     5d/pop-to-ebp
10901     c3/return
10902 
10903 test-parse-mu-stmt-with-comma:
10904     # . prologue
10905     55/push-ebp
10906     89/<- %ebp 4/r32/esp
10907     # setup
10908     (clear-stream _test-input-stream)
10909     (write _test-input-stream "copy-to n, 3\n")
10910     # var vars/ecx: (stack (addr var) 16)
10911     81 5/subop/subtract %esp 0xc0/imm32
10912     68/push 0xc0/imm32/size
10913     68/push 0/imm32/top
10914     89/<- %ecx 4/r32/esp
10915     (clear-stack %ecx)
10916     # var v/edx: (handle var)
10917     68/push 0/imm32
10918     68/push 0/imm32
10919     89/<- %edx 4/r32/esp
10920     # var s/eax: (handle array byte)
10921     68/push 0/imm32
10922     68/push 0/imm32
10923     89/<- %eax 4/r32/esp
10924     # v = new var("n")
10925     (copy-array Heap "n" %eax)
10926     (new-var Heap *eax *(eax+4) %edx)
10927     #
10928     (push %ecx *edx)
10929     (push %ecx *(edx+4))
10930     (push %ecx 0)
10931     # var out/eax: (handle stmt)
10932     68/push 0/imm32
10933     68/push 0/imm32
10934     89/<- %eax 4/r32/esp
10935     # convert
10936     (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
10937     # var out-addr/edx: (addr stmt) = lookup(*out)
10938     (lookup *eax *(eax+4))  # => eax
10939     89/<- %edx 0/r32/eax
10940     # out->tag
10941     (check-ints-equal *edx 1 "F - test-parse-mu-stmt-with-comma/tag")  # Stmt-tag is Stmt1
10942     # out->operation
10943     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
10944     (check-strings-equal %eax "copy-to" "F - test-parse-mu-stmt-with-comma/name")  # Stmt1-operation
10945     # out->inouts->value->name
10946     # . eax = out->inouts
10947     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
10948     # . eax = out->inouts->value
10949     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10950     # . eax = out->inouts->value->name
10951     (lookup *eax *(eax+4))  # Var-name Var-name => eax
10952     # .
10953     (check-strings-equal %eax "n" "F - test-parse-mu-stmt-with-comma/inout:0")
10954     # . epilogue
10955     89/<- %esp 5/r32/ebp
10956     5d/pop-to-ebp
10957     c3/return
10958 
10959 new-var:  # ad: (addr allocation-descriptor), name: (handle array byte), out: (addr handle var)
10960     # . prologue
10961     55/push-ebp
10962     89/<- %ebp 4/r32/esp
10963     # . save registers
10964     50/push-eax
10965     51/push-ecx
10966     # ecx = out
10967     8b/-> *(ebp+0x14) 1/r32/ecx
10968     #
10969     (allocate *(ebp+8) *Var-size %ecx)
10970     # var out-addr/eax: (addr var)
10971     (lookup *ecx *(ecx+4))  # => eax
10972     # out-addr->name = name
10973     8b/-> *(ebp+0xc) 1/r32/ecx
10974     89/<- *eax 1/r32/ecx  # Var-name
10975     8b/-> *(ebp+0x10) 1/r32/ecx
10976     89/<- *(eax+4) 1/r32/ecx  # Var-name
10977 #?     (write-buffered Stderr "var ")
10978 #?     (lookup *(ebp+0xc) *(ebp+0x10))
10979 #?     (write-buffered Stderr %eax)
10980 #?     (write-buffered Stderr " at ")
10981 #?     8b/-> *(ebp+0x14) 1/r32/ecx
10982 #?     (lookup *ecx *(ecx+4))  # => eax
10983 #?     (write-int32-hex-buffered Stderr %eax)
10984 #?     (write-buffered Stderr Newline)
10985 #?     (flush Stderr)
10986 $new-var:end:
10987     # . restore registers
10988     59/pop-to-ecx
10989     58/pop-to-eax
10990     # . epilogue
10991     89/<- %esp 5/r32/ebp
10992     5d/pop-to-ebp
10993     c3/return
10994 
10995 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)
10996     # . prologue
10997     55/push-ebp
10998     89/<- %ebp 4/r32/esp
10999     # . save registers
11000     50/push-eax
11001     51/push-ecx
11002     # if (!is-hex-int?(name)) abort
11003     (is-hex-int? *(ebp+0xc))  # => eax
11004     3d/compare-eax-and 0/imm32/false
11005     0f 84/jump-if-= $new-literal-integer:abort/disp32
11006     # a little more error-checking
11007     (check-mu-hex-int *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c))
11008     # out = new var(s)
11009     (new-var-from-slice *(ebp+8) *(ebp+0xc) *(ebp+0x10))
11010     # var out-addr/ecx: (addr var) = lookup(*out)
11011     8b/-> *(ebp+0x10) 0/r32/eax
11012     (lookup *eax *(eax+4))  # => eax
11013     89/<- %ecx 0/r32/eax
11014     # out-addr->block-depth = *Curr-block-depth
11015     8b/-> *Curr-block-depth 0/r32/eax
11016     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
11017     # out-addr->type = new tree()
11018     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
11019     (allocate *(ebp+8) *Type-tree-size %eax)
11020     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
11021     c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
11022     # nothing else to do; default type is 'literal'
11023 $new-literal-integer:end:
11024     # . reclaim locals
11025     81 0/subop/add %esp 8/imm32
11026     # . restore registers
11027     59/pop-to-ecx
11028     58/pop-to-eax
11029     # . epilogue
11030     89/<- %esp 5/r32/ebp
11031     5d/pop-to-ebp
11032     c3/return
11033 
11034 $new-literal-integer:abort:
11035     (write-buffered *(ebp+0x18) "fn ")
11036     8b/-> *(ebp+0x14) 0/r32/eax
11037     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11038     (write-buffered *(ebp+0x18) %eax)
11039     (write-buffered *(ebp+0x18) ": variable '")
11040     (write-slice-buffered *(ebp+0x18) *(ebp+0xc))
11041     (write-buffered *(ebp+0x18) "' cannot begin with a digit (or do you have a typo in a number?)\n")
11042     (flush *(ebp+0x18))
11043     (stop *(ebp+0x1c) 1)
11044     # never gets here
11045 
11046 # precondition: name is a valid hex integer; require a '0x' prefix
11047 check-mu-hex-int:  # name: (addr slice), err: (addr buffered-file), ed: (addr exit-descriptor)
11048     # . prologue
11049     55/push-ebp
11050     89/<- %ebp 4/r32/esp
11051     # . save registers
11052     50/push-eax
11053     51/push-ecx
11054     52/push-edx
11055     # ecx = name
11056     8b/-> *(ebp+8) 1/r32/ecx
11057     # var start/edx: (addr byte) = name->start
11058     8b/-> *ecx 2/r32/edx
11059     # if (*start == '-') ++start
11060     b8/copy-to-eax 0/imm32
11061     8a/copy-byte *edx 0/r32/AL
11062     3d/compare-eax-and 0x2d/imm32/dash
11063     {
11064       75/jump-if-!= break/disp8
11065       42/increment-edx
11066     }
11067     # var end/ecx: (addr byte) = name->end
11068     8b/-> *(ecx+4) 1/r32/ecx
11069     # var len/eax: int = name->end - name->start
11070     89/<- %eax 1/r32/ecx
11071     29/subtract-from %eax 2/r32/edx
11072     # if (len <= 1) return
11073     3d/compare-eax-with 1/imm32
11074     0f 8e/jump-if-<= $check-mu-hex-int:end/disp32
11075 $check-mu-hex-int:length->-1:
11076     # if slice-starts-with?({start, end}, "0x") return
11077     # . var tmp = {start, end}
11078     51/push-ecx
11079     52/push-edx
11080     89/<- %eax 4/r32/esp
11081     # .
11082     (slice-starts-with? %eax "0x")  # => eax
11083     # . reclaim tmp
11084     81 0/subop/add %esp 8/imm32
11085     # .
11086     3d/compare-eax-with 0/imm32/false
11087     75/jump-if-!= $check-mu-hex-int:end/disp8
11088 $check-mu-hex-int:abort:
11089     # otherwise abort
11090     (write-buffered *(ebp+0xc) "literal integers are always hex in Mu; either start '")
11091     (write-slice-buffered *(ebp+0xc) *(ebp+8))
11092     (write-buffered *(ebp+0xc) "' with a '0x' to be unambiguous, or convert it to decimal.\n")
11093     (flush *(ebp+0xc))
11094     (stop *(ebp+0x10) 1)
11095 $check-mu-hex-int:end:
11096     # . restore registers
11097     5a/pop-to-edx
11098     59/pop-to-ecx
11099     58/pop-to-eax
11100     # . epilogue
11101     89/<- %esp 5/r32/ebp
11102     5d/pop-to-ebp
11103     c3/return
11104 
11105 new-literal:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
11106     # . prologue
11107     55/push-ebp
11108     89/<- %ebp 4/r32/esp
11109     # . save registers
11110     50/push-eax
11111     51/push-ecx
11112     # var s/ecx: (handle array byte)
11113     68/push 0/imm32
11114     68/push 0/imm32
11115     89/<- %ecx 4/r32/esp
11116     # s = slice-to-string(name)
11117     (slice-to-string Heap *(ebp+0xc) %ecx)
11118     # allocate to out
11119     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
11120     # var out-addr/ecx: (addr var) = lookup(*out)
11121     8b/-> *(ebp+0x10) 1/r32/ecx
11122     (lookup *ecx *(ecx+4))  # => eax
11123     89/<- %ecx 0/r32/eax
11124     # out-addr->block-depth = *Curr-block-depth
11125     8b/-> *Curr-block-depth 0/r32/eax
11126     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
11127     # out-addr->type/eax = new type
11128     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
11129     (allocate *(ebp+8) *Type-tree-size %eax)
11130     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
11131     # nothing else to do; default type is 'literal'
11132     c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
11133 $new-literal:end:
11134     # . reclaim locals
11135     81 0/subop/add %esp 8/imm32
11136     # . restore registers
11137     59/pop-to-ecx
11138     58/pop-to-eax
11139     # . epilogue
11140     89/<- %esp 5/r32/ebp
11141     5d/pop-to-ebp
11142     c3/return
11143 
11144 new-var-from-slice:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
11145     # . prologue
11146     55/push-ebp
11147     89/<- %ebp 4/r32/esp
11148     # . save registers
11149     51/push-ecx
11150     # var tmp/ecx: (handle array byte)
11151     68/push 0/imm32
11152     68/push 0/imm32
11153     89/<- %ecx 4/r32/esp
11154     # tmp = slice-to-string(name)
11155     (slice-to-string Heap *(ebp+0xc) %ecx)
11156     # out = new-var(tmp)
11157     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
11158 $new-var-from-slice:end:
11159     # . reclaim locals
11160     81 0/subop/add %esp 8/imm32
11161     # . restore registers
11162     59/pop-to-ecx
11163     # . epilogue
11164     89/<- %esp 5/r32/ebp
11165     5d/pop-to-ebp
11166     c3/return
11167 
11168 new-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
11169     # . prologue
11170     55/push-ebp
11171     89/<- %ebp 4/r32/esp
11172     # . save registers
11173     50/push-eax
11174     51/push-ecx
11175     #
11176     (allocate *(ebp+8) *Stmt-size *(ebp+0x14))
11177     # var out-addr/eax: (addr stmt) = lookup(*out)
11178     8b/-> *(ebp+0x14) 0/r32/eax
11179     (lookup *eax *(eax+4))  # => eax
11180     # out-addr->tag = stmt
11181     c7 0/subop/copy *eax 2/imm32/tag/var-on-stack  # Stmt-tag
11182     # result->var = var
11183     8b/-> *(ebp+0xc) 1/r32/ecx
11184     89/<- *(eax+4) 1/r32/ecx  # Vardef-var
11185     8b/-> *(ebp+0x10) 1/r32/ecx
11186     89/<- *(eax+8) 1/r32/ecx  # Vardef-var
11187 $new-var-def:end:
11188     # . restore registers
11189     59/pop-to-ecx
11190     58/pop-to-eax
11191     # . epilogue
11192     89/<- %esp 5/r32/ebp
11193     5d/pop-to-ebp
11194     c3/return
11195 
11196 new-reg-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
11197     # . prologue
11198     55/push-ebp
11199     89/<- %ebp 4/r32/esp
11200     # . save registers
11201     50/push-eax
11202     # eax = out
11203     8b/-> *(ebp+0x14) 0/r32/eax
11204     #
11205     (allocate *(ebp+8) *Stmt-size %eax)
11206     # var out-addr/eax: (addr stmt) = lookup(*out)
11207     (lookup *eax *(eax+4))  # => eax
11208     # set tag
11209     c7 0/subop/copy *eax 3/imm32/tag/var-in-register  # Stmt-tag
11210     # set output
11211     8d/copy-address *(eax+0x14) 0/r32/eax  # Regvardef-outputs
11212     (append-stmt-var Heap  *(ebp+0xc) *(ebp+0x10)  0 0  0  %eax)
11213 $new-reg-var-def:end:
11214     # . restore registers
11215     58/pop-to-eax
11216     # . epilogue
11217     89/<- %esp 5/r32/ebp
11218     5d/pop-to-ebp
11219     c3/return
11220 
11221 append-list:  # ad: (addr allocation-descriptor), value: (handle _type), list: (handle list _type), out: (addr handle list _type)
11222     # . prologue
11223     55/push-ebp
11224     89/<- %ebp 4/r32/esp
11225     # . save registers
11226     50/push-eax
11227     51/push-ecx
11228     57/push-edi
11229     # edi = out
11230     8b/-> *(ebp+0x1c) 7/r32/edi
11231     # *out = new list
11232     (allocate *(ebp+8) *List-size %edi)
11233     # var out-addr/edi: (addr list _type) = lookup(*out)
11234     (lookup *edi *(edi+4))  # => eax
11235     89/<- %edi 0/r32/eax
11236     # out-addr->value = value
11237     8b/-> *(ebp+0xc) 0/r32/eax
11238     89/<- *edi 0/r32/eax  # List-value
11239     8b/-> *(ebp+0x10) 0/r32/eax
11240     89/<- *(edi+4) 0/r32/eax  # List-value
11241     # if (list == null) return
11242     81 7/subop/compare *(ebp+0x14) 0/imm32
11243     74/jump-if-= $append-list:end/disp8
11244     # otherwise append
11245 $append-list:non-empty-list:
11246     # var curr/eax: (addr list _type) = lookup(list)
11247     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
11248     # while (curr->next != null) curr = curr->next
11249     {
11250       81 7/subop/compare *(eax+8) 0/imm32  # List-next
11251       74/jump-if-= break/disp8
11252       # curr = lookup(curr->next)
11253       (lookup *(eax+8) *(eax+0xc))  # List-next, List-next => eax
11254       #
11255       eb/jump loop/disp8
11256     }
11257     # edi = out
11258     8b/-> *(ebp+0x1c) 7/r32/edi
11259     # curr->next = out
11260     8b/-> *edi 1/r32/ecx
11261     89/<- *(eax+8) 1/r32/ecx  # List-next
11262     8b/-> *(edi+4) 1/r32/ecx
11263     89/<- *(eax+0xc) 1/r32/ecx  # List-next
11264     # out = list
11265     8b/-> *(ebp+0x14) 1/r32/ecx
11266     89/<- *edi 1/r32/ecx
11267     8b/-> *(ebp+0x18) 1/r32/ecx
11268     89/<- *(edi+4) 1/r32/ecx
11269 $append-list:end:
11270     # . restore registers
11271     5f/pop-to-edi
11272     59/pop-to-ecx
11273     58/pop-to-eax
11274     # . epilogue
11275     89/<- %esp 5/r32/ebp
11276     5d/pop-to-ebp
11277     c3/return
11278 
11279 append-stmt-var:  # ad: (addr allocation-descriptor), v: (handle var), vars: (handle stmt-var), is-deref?: boolean, out: (addr handle stmt-var)
11280     # . prologue
11281     55/push-ebp
11282     89/<- %ebp 4/r32/esp
11283     # . save registers
11284     50/push-eax
11285     51/push-ecx
11286     57/push-edi
11287     # edi = out
11288     8b/-> *(ebp+0x20) 7/r32/edi
11289     # out = new stmt-var
11290     (allocate *(ebp+8) *Stmt-var-size %edi)
11291     # var out-addr/ecx: (addr stmt-var) = lookup(*out)
11292     (lookup *edi *(edi+4))  # => eax
11293     89/<- %ecx 0/r32/eax
11294     # out-addr->value = v
11295     8b/-> *(ebp+0xc) 0/r32/eax
11296     89/<- *ecx 0/r32/eax  # Stmt-var-value
11297     8b/-> *(ebp+0x10) 0/r32/eax
11298     89/<- *(ecx+4) 0/r32/eax  # Stmt-var-value
11299     # out-addr->is-deref? = is-deref?
11300     8b/-> *(ebp+0x1c) 0/r32/eax
11301     89/<- *(ecx+0x10) 0/r32/eax  # Stmt-var-is-deref
11302     # if (vars == null) return result
11303     81 7/subop/compare *(ebp+0x14) 0/imm32/null
11304     74/jump-if-= $append-stmt-var:end/disp8
11305     # otherwise append
11306     # var curr/eax: (addr stmt-var) = lookup(vars)
11307     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
11308     # while (curr->next != null) curr = curr->next
11309     {
11310       81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
11311       74/jump-if-= break/disp8
11312       # curr = lookup(curr->next)
11313       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next, Stmt-var-next => eax
11314       #
11315       eb/jump loop/disp8
11316     }
11317     # curr->next = out
11318     8b/-> *edi 1/r32/ecx
11319     89/<- *(eax+8) 1/r32/ecx  # Stmt-var-next
11320     8b/-> *(edi+4) 1/r32/ecx
11321     89/<- *(eax+0xc) 1/r32/ecx  # Stmt-var-next
11322     # out = vars
11323     8b/-> *(ebp+0x14) 1/r32/ecx
11324     89/<- *edi 1/r32/ecx
11325     8b/-> *(ebp+0x18) 1/r32/ecx
11326     89/<- *(edi+4) 1/r32/ecx
11327 $append-stmt-var:end:
11328     # . restore registers
11329     5f/pop-to-edi
11330     59/pop-to-ecx
11331     58/pop-to-eax
11332     # . epilogue
11333     89/<- %esp 5/r32/ebp
11334     5d/pop-to-ebp
11335     c3/return
11336 
11337 append-to-block:  # ad: (addr allocation-descriptor), block: (addr block), x: (handle stmt)
11338     # . prologue
11339     55/push-ebp
11340     89/<- %ebp 4/r32/esp
11341     # . save registers
11342     50/push-eax
11343     56/push-esi
11344     # esi = block
11345     8b/-> *(ebp+0xc) 6/r32/esi
11346     # block->stmts = append(x, block->stmts)
11347     8d/copy-address *(esi+4) 0/r32/eax  # Block-stmts
11348     (append-list *(ebp+8)  *(ebp+0x10) *(ebp+0x14)  *(esi+4) *(esi+8)  %eax)  # ad, x, x, Block-stmts, Block-stmts
11349 $append-to-block:end:
11350     # . restore registers
11351     5e/pop-to-esi
11352     58/pop-to-eax
11353     # . epilogue
11354     89/<- %esp 5/r32/ebp
11355     5d/pop-to-ebp
11356     c3/return
11357 
11358 ## Parsing types
11359 # We need to create metadata on user-defined types, and we need to use this
11360 # metadata as we parse instructions.
11361 # However, we also want to allow types to be used before their definitions.
11362 # This means we can't ever assume any type data structures exist.
11363 
11364 lookup-or-create-constant:  # container: (addr stmt-var), field-name: (addr slice), out: (addr handle var)
11365     # . prologue
11366     55/push-ebp
11367     89/<- %ebp 4/r32/esp
11368     # . save registers
11369     50/push-eax
11370     56/push-esi
11371     # var container-type/esi: type-id
11372     (container-type *(ebp+8))  # => eax
11373     89/<- %esi 0/r32/eax
11374     # var tmp/eax: (handle typeinfo) = find-or-create-typeinfo(container-type)
11375     68/push 0/imm32
11376     68/push 0/imm32
11377     89/<- %eax 4/r32/esp
11378     (find-or-create-typeinfo %esi %eax)
11379     # var tmp-addr/eax: (addr typeinfo) = lookup(tmp)
11380     (lookup *eax *(eax+4))  # => eax
11381     # result = find-or-create-typeinfo-output-var(typeinfo, field-name)
11382 #?     (write-buffered Stderr "constant: ")
11383 #?     (write-slice-buffered Stderr *(ebp+0xc))
11384 #?     (write-buffered Stderr Newline)
11385 #?     (flush Stderr)
11386     (find-or-create-typeinfo-output-var %eax *(ebp+0xc) *(ebp+0x10))
11387 #?     8b/-> *(ebp+0x10) 0/r32/eax
11388 #?     (write-buffered Stderr "@")
11389 #?     (lookup *eax *(eax+4))
11390 #?     (write-int32-hex-buffered Stderr %eax)
11391 #?     (lookup *eax *(eax+4))
11392 #?     (write-buffered Stderr %eax)
11393 #?     (write-buffered Stderr Newline)
11394 #?     (flush Stderr)
11395 #?     (write-buffered Stderr "offset: ")
11396 #?     8b/-> *(eax+0x14) 0/r32/eax
11397 #?     (write-int32-hex-buffered Stderr %eax)
11398 #?     (write-buffered Stderr Newline)
11399 #?     (flush Stderr)
11400 $lookup-or-create-constant:end:
11401     # . reclaim locals
11402     81 0/subop/add %esp 8/imm32
11403     # . restore registers
11404     5e/pop-to-esi
11405     58/pop-to-eax
11406     # . epilogue
11407     89/<- %esp 5/r32/ebp
11408     5d/pop-to-ebp
11409     c3/return
11410 
11411 # if addr var:
11412 #   container->var->type->right->left->value
11413 # otherwise
11414 #   container->var->type->value
11415 container-type:  # container: (addr stmt-var) -> result/eax: type-id
11416     # . prologue
11417     55/push-ebp
11418     89/<- %ebp 4/r32/esp
11419     #
11420     8b/-> *(ebp+8) 0/r32/eax
11421     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11422     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11423     {
11424       81 7/subop/compare *(eax+8) 0/imm32  # Type-tree-right
11425       74/jump-if-= break/disp8
11426       (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
11427       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
11428     }
11429     8b/-> *(eax+4) 0/r32/eax  # Type-tree-value
11430 $container-type:end:
11431     # . epilogue
11432     89/<- %esp 5/r32/ebp
11433     5d/pop-to-ebp
11434     c3/return
11435 
11436 is-container?:  # t: type-id -> result/eax: boolean
11437     # . prologue
11438     55/push-ebp
11439     89/<- %ebp 4/r32/esp
11440     #
11441     8b/-> *(ebp+8) 0/r32/eax
11442     c1/shift 4/subop/left %eax 2/imm8
11443     3b/compare 0/r32/eax *Primitive-type-ids
11444     0f 9d/set-if->= %al
11445     81 4/subop/and %eax 0xff/imm32
11446 $is-container?:end:
11447     # . epilogue
11448     89/<- %esp 5/r32/ebp
11449     5d/pop-to-ebp
11450     c3/return
11451 
11452 find-or-create-typeinfo:  # t: type-id, out: (addr handle typeinfo)
11453     # . prologue
11454     55/push-ebp
11455     89/<- %ebp 4/r32/esp
11456     # . save registers
11457     50/push-eax
11458     51/push-ecx
11459     52/push-edx
11460     57/push-edi
11461     # edi = out
11462     8b/-> *(ebp+0xc) 7/r32/edi
11463     # var fields/ecx: (handle table (handle array byte) (handle typeinfo-entry))
11464     68/push 0/imm32
11465     68/push 0/imm32
11466     89/<- %ecx 4/r32/esp
11467     # find-typeinfo(t, out)
11468     (find-typeinfo *(ebp+8) %edi)
11469     {
11470       # if (*out != 0) break
11471       81 7/subop/compare *edi 0/imm32
11472       0f 85/jump-if-!= break/disp32
11473 $find-or-create-typeinfo:create:
11474       # *out = allocate
11475       (allocate Heap *Typeinfo-size %edi)
11476       # var tmp/eax: (addr typeinfo) = lookup(*out)
11477       (lookup *edi *(edi+4))  # => eax
11478 #?     (write-buffered Stderr "created typeinfo at ")
11479 #?     (write-int32-hex-buffered Stderr %eax)
11480 #?     (write-buffered Stderr " for type-id ")
11481 #?     (write-int32-hex-buffered Stderr *(ebp+8))
11482 #?     (write-buffered Stderr Newline)
11483 #?     (flush Stderr)
11484       # tmp->id = t
11485       8b/-> *(ebp+8) 2/r32/edx
11486       89/<- *eax 2/r32/edx  # Typeinfo-id
11487       # tmp->fields = new table
11488       # . fields = new table
11489       (new-stream Heap 0x40 *Typeinfo-fields-row-size %ecx)
11490       # . tmp->fields = fields
11491       8b/-> *ecx 2/r32/edx
11492       89/<- *(eax+4) 2/r32/edx  # Typeinfo-fields
11493       8b/-> *(ecx+4) 2/r32/edx
11494       89/<- *(eax+8) 2/r32/edx  # Typeinfo-fields
11495       # tmp->next = Program->types
11496       8b/-> *_Program-types 1/r32/ecx
11497       89/<- *(eax+0x10) 1/r32/ecx  # Typeinfo-next
11498       8b/-> *_Program-types->payload 1/r32/ecx
11499       89/<- *(eax+0x14) 1/r32/ecx  # Typeinfo-next
11500       # Program->types = out
11501       8b/-> *edi 1/r32/ecx
11502       89/<- *_Program-types 1/r32/ecx
11503       8b/-> *(edi+4) 1/r32/ecx
11504       89/<- *_Program-types->payload 1/r32/ecx
11505     }
11506 $find-or-create-typeinfo:end:
11507     # . reclaim locals
11508     81 0/subop/add %esp 8/imm32
11509     # . restore registers
11510     5f/pop-to-edi
11511     5a/pop-to-edx
11512     59/pop-to-ecx
11513     58/pop-to-eax
11514     # . epilogue
11515     89/<- %esp 5/r32/ebp
11516     5d/pop-to-ebp
11517     c3/return
11518 
11519 find-typeinfo:  # t: type-id, out: (addr handle typeinfo)
11520     # . prologue
11521     55/push-ebp
11522     89/<- %ebp 4/r32/esp
11523     # . save registers
11524     50/push-eax
11525     51/push-ecx
11526     52/push-edx
11527     57/push-edi
11528     # ecx = t
11529     8b/-> *(ebp+8) 1/r32/ecx
11530     # edi = out
11531     8b/-> *(ebp+0xc) 7/r32/edi
11532     # *out = Program->types
11533     8b/-> *_Program-types 0/r32/eax
11534     89/<- *edi 0/r32/eax
11535     8b/-> *_Program-types->payload 0/r32/eax
11536     89/<- *(edi+4) 0/r32/eax
11537     {
11538 $find-typeinfo:loop:
11539       # if (*out == 0) break
11540       81 7/subop/compare *edi 0/imm32
11541       74/jump-if-= break/disp8
11542 $find-typeinfo:check:
11543       # var tmp/eax: (addr typeinfo) = lookup(*out)
11544       (lookup *edi *(edi+4))  # => eax
11545       # if (tmp->id == t) break
11546       39/compare *eax 1/r32/ecx  # Typeinfo-id
11547       74/jump-if-= break/disp8
11548 $find-typeinfo:continue:
11549       # *out = tmp->next
11550       8b/-> *(eax+0x10) 2/r32/edx  # Typeinfo-next
11551       89/<- *edi 2/r32/edx
11552       8b/-> *(eax+0x14) 2/r32/edx  # Typeinfo-next
11553       89/<- *(edi+4) 2/r32/edx
11554       #
11555       eb/jump loop/disp8
11556     }
11557 $find-typeinfo:end:
11558     # . restore registers
11559     5f/pop-to-edi
11560     5a/pop-to-edx
11561     59/pop-to-ecx
11562     58/pop-to-eax
11563     # . epilogue
11564     89/<- %esp 5/r32/ebp
11565     5d/pop-to-ebp
11566     c3/return
11567 
11568 find-or-create-typeinfo-output-var:  # T: (addr typeinfo), f: (addr slice), out: (addr handle var)
11569     # . prologue
11570     55/push-ebp
11571     89/<- %ebp 4/r32/esp
11572     # . save registers
11573     50/push-eax
11574     52/push-edx
11575     57/push-edi
11576     # var dest/edi: (handle typeinfo-entry)
11577     68/push 0/imm32
11578     68/push 0/imm32
11579     89/<- %edi 4/r32/esp
11580     # find-or-create-typeinfo-fields(T, f, dest)
11581     (find-or-create-typeinfo-fields *(ebp+8) *(ebp+0xc) %edi)
11582     # var dest-addr/edi: (addr typeinfo-entry) = lookup(dest)
11583     (lookup *edi *(edi+4))  # => eax
11584     89/<- %edi 0/r32/eax
11585     # if dest-addr->output-var doesn't exist, create it
11586     {
11587       81 7/subop/compare *(edi+0xc) 0/imm32  # Typeinfo-entry-output-var
11588       0f 85/jump-if-!= break/disp32
11589       # dest-addr->output-var = new var(dummy name, type, -1 offset)
11590       # . var name/eax: (handle array byte) = "field"
11591       68/push 0/imm32
11592       68/push 0/imm32
11593       89/<- %eax 4/r32/esp
11594       (slice-to-string Heap *(ebp+0xc) %eax)
11595       # . new var
11596       8d/copy-address *(edi+0xc) 2/r32/edx
11597       (new-var Heap  *eax *(eax+4)  %edx)
11598       # . reclaim name
11599       81 0/subop/add %esp 8/imm32
11600       # var result/edx: (addr var) = lookup(dest-addr->output-var)
11601       (lookup *(edi+0xc) *(edi+0x10))  # => eax
11602       89/<- %edx 0/r32/eax
11603       # result->type = new constant type
11604       8d/copy-address *(edx+8) 0/r32/eax  # Var-type
11605       (allocate Heap *Type-tree-size %eax)
11606       (lookup *(edx+8) *(edx+0xc))  # => eax
11607       c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
11608       c7 0/subop/copy *(eax+4) 6/imm32/constant  # Type-tree-value
11609       c7 0/subop/copy *(eax+8) 0/imm32  # Type-tree-left
11610       c7 0/subop/copy *(eax+0xc) 0/imm32  # Type-tree-right
11611       c7 0/subop/copy *(eax+0x10) 0/imm32  # Type-tree-right
11612       # result->offset isn't filled out yet
11613       c7 0/subop/copy *(edx+0x14) -1/imm32/uninitialized  # Var-offset
11614     }
11615     # out = dest-addr->output-var
11616     8b/-> *(ebp+0x10) 2/r32/edx
11617     8b/-> *(edi+0xc) 0/r32/eax  # Typeinfo-entry-output-var
11618     89/<- *edx 0/r32/eax
11619     8b/-> *(edi+0x10) 0/r32/eax  # Typeinfo-entry-output-var
11620     89/<- *(edx+4) 0/r32/eax
11621 $find-or-create-typeinfo-output-var:end:
11622     # . reclaim locals
11623     81 0/subop/add %esp 8/imm32
11624     # . restore registers
11625     5f/pop-to-edi
11626     5a/pop-to-edx
11627     58/pop-to-eax
11628     # . epilogue
11629     89/<- %esp 5/r32/ebp
11630     5d/pop-to-ebp
11631     c3/return
11632 
11633 find-or-create-typeinfo-fields:  # T: (addr typeinfo), f: (addr slice), out: (addr handle typeinfo-entry)
11634     # . prologue
11635     55/push-ebp
11636     89/<- %ebp 4/r32/esp
11637     # . save registers
11638     50/push-eax
11639     56/push-esi
11640     57/push-edi
11641     # eax = lookup(T->fields)
11642     8b/-> *(ebp+8) 0/r32/eax
11643     (lookup *(eax+4) *(eax+8))  # Typeinfo-fields Typeinfo-fields => eax
11644     # edi = out
11645     8b/-> *(ebp+0x10) 7/r32/edi
11646     # var src/esi: (addr handle typeinfo-entry) = get-or-insert-slice(T->fields, f)
11647     (get-or-insert-slice %eax *(ebp+0xc) *Typeinfo-fields-row-size Heap)  # => eax
11648     89/<- %esi 0/r32/eax
11649     # if src doesn't exist, allocate it
11650     {
11651       81 7/subop/compare *esi 0/imm32
11652       75/jump-if-!= break/disp8
11653       (allocate Heap *Typeinfo-entry-size %esi)
11654 #?       (write-buffered Stderr "handle at ")
11655 #?       (write-int32-hex-buffered Stderr %esi)
11656 #?       (write-buffered Stderr ": ")
11657 #?       (write-int32-hex-buffered Stderr *esi)
11658 #?       (write-buffered Stderr " ")
11659 #?       (write-int32-hex-buffered Stderr *(esi+4))
11660 #?       (write-buffered Stderr Newline)
11661 #?       (flush Stderr)
11662 #?       (lookup *esi *(esi+4))
11663 #?       (write-buffered Stderr "created typeinfo fields at ")
11664 #?       (write-int32-hex-buffered Stderr %esi)
11665 #?       (write-buffered Stderr " for ")
11666 #?       (write-int32-hex-buffered Stderr *(ebp+8))
11667 #?       (write-buffered Stderr Newline)
11668 #?       (flush Stderr)
11669     }
11670     # *out = src
11671     # . *edi = *src
11672     8b/-> *esi 0/r32/eax
11673     89/<- *edi 0/r32/eax
11674     8b/-> *(esi+4) 0/r32/eax
11675     89/<- *(edi+4) 0/r32/eax
11676 $find-or-create-typeinfo-fields:end:
11677     # . restore registers
11678     5f/pop-to-edi
11679     5e/pop-to-esi
11680     58/pop-to-eax
11681     # . epilogue
11682     89/<- %esp 5/r32/ebp
11683     5d/pop-to-ebp
11684     c3/return
11685 
11686 populate-mu-type:  # in: (addr stream byte), t: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
11687     # pseudocode:
11688     #   var line: (stream byte 512)
11689     #   curr-index = 0
11690     #   while true
11691     #     clear-stream(line)
11692     #     read-line-buffered(in, line)
11693     #     if line->write == 0
11694     #       abort
11695     #     word-slice = next-mu-token(line)
11696     #     if slice-empty?(word-slice)               # end of line
11697     #       continue
11698     #     if slice-equal?(word-slice, "}")
11699     #       break
11700     #     var v: (handle var) = parse-var-with-type(word-slice, line)
11701     #     var r: (handle typeinfo-fields) = find-or-create-typeinfo-fields(t, word-slice/v->name)
11702     #     TODO: ensure that r->first is null
11703     #     r->index = curr-index
11704     #     curr-index++
11705     #     r->input-var = v
11706     #     if r->output-var == 0
11707     #       r->output-var = new literal
11708     #     TODO: ensure nothing else in line
11709     # t->total-size-in-bytes = -2 (not yet initialized)
11710     #
11711     # . prologue
11712     55/push-ebp
11713     89/<- %ebp 4/r32/esp
11714     # var curr-index: int at *(ebp-4)
11715     68/push 0/imm32
11716     # . save registers
11717     50/push-eax
11718     51/push-ecx
11719     52/push-edx
11720     53/push-ebx
11721     56/push-esi
11722     57/push-edi
11723     # edi = t
11724     8b/-> *(ebp+0xc) 7/r32/edi
11725     # var line/ecx: (stream byte 512)
11726     81 5/subop/subtract %esp 0x200/imm32
11727     68/push 0x200/imm32/size
11728     68/push 0/imm32/read
11729     68/push 0/imm32/write
11730     89/<- %ecx 4/r32/esp
11731     # var word-slice/edx: slice
11732     68/push 0/imm32/end
11733     68/push 0/imm32/start
11734     89/<- %edx 4/r32/esp
11735     # var v/esi: (handle var)
11736     68/push 0/imm32
11737     68/push 0/imm32
11738     89/<- %esi 4/r32/esp
11739     # var r/ebx: (handle typeinfo-entry)
11740     68/push 0/imm32
11741     68/push 0/imm32
11742     89/<- %ebx 4/r32/esp
11743     {
11744 $populate-mu-type:line-loop:
11745       (clear-stream %ecx)
11746       (read-line-buffered *(ebp+8) %ecx)
11747       # if (line->write == 0) abort
11748       81 7/subop/compare *ecx 0/imm32
11749       0f 84/jump-if-= $populate-mu-type:error1/disp32
11750 +--  6 lines: #?       # dump line ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
11756       (next-mu-token %ecx %edx)
11757       # if slice-empty?(word-slice) continue
11758       (slice-empty? %edx)  # => eax
11759       3d/compare-eax-and 0/imm32
11760       0f 85/jump-if-!= loop/disp32
11761       # if slice-equal?(word-slice, "}") break
11762       (slice-equal? %edx "}")
11763       3d/compare-eax-and 0/imm32
11764       0f 85/jump-if-!= break/disp32
11765 $populate-mu-type:parse-element:
11766       # v = parse-var-with-type(word-slice, first-line)
11767       # must do this first to strip the trailing ':' from word-slice before
11768       # using it in find-or-create-typeinfo-fields below
11769       # TODO: clean up that mutation in parse-var-with-type
11770       (parse-var-with-type %edx %ecx %esi *(ebp+0x10) *(ebp+0x14))
11771       # if v is an addr, abort
11772       (lookup *esi *(esi+4))  # => eax
11773       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11774       (is-mu-addr-type? %eax)  # => eax
11775       3d/compare-eax-and 0/imm32/false
11776       0f 85/jump-if-!= $populate-mu-type:error2/disp32
11777       # if v is an array, abort  (we could support it, but initialization gets complex)
11778       (lookup *esi *(esi+4))  # => eax
11779       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11780       (is-mu-array-type? %eax)  # => eax
11781       3d/compare-eax-and 0/imm32/false
11782       0f 85/jump-if-!= $populate-mu-type:error3/disp32
11783       # if v is a byte, abort
11784       (lookup *esi *(esi+4))  # => eax
11785       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11786       (is-simple-mu-type? %eax 8)  # byte => eax
11787       3d/compare-eax-and 0/imm32/false
11788       0f 85/jump-if-!= $populate-mu-type:error4/disp32
11789       # if v is a slice, abort
11790       (lookup *esi *(esi+4))  # => eax
11791       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11792       (is-simple-mu-type? %eax 0xc)  # slice => eax
11793       3d/compare-eax-and 0/imm32/false
11794       0f 85/jump-if-!= $populate-mu-type:error5/disp32
11795       # if v is a stream, abort  (we could support it, but initialization gets even more complex)
11796       (lookup *esi *(esi+4))  # => eax
11797       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11798       (is-mu-stream-type? %eax)  # => eax
11799       3d/compare-eax-and 0/imm32/false
11800       0f 85/jump-if-!= $populate-mu-type:error6/disp32
11801       # var tmp/ecx
11802       51/push-ecx
11803 $populate-mu-type:create-typeinfo-fields:
11804       # var r/ebx: (handle typeinfo-entry)
11805       (find-or-create-typeinfo-fields %edi %edx %ebx)
11806       # r->index = curr-index
11807       (lookup *ebx *(ebx+4))  # => eax
11808       8b/-> *(ebp-4) 1/r32/ecx
11809 #?       (write-buffered Stderr "saving index ")
11810 #?       (write-int32-hex-buffered Stderr %ecx)
11811 #?       (write-buffered Stderr " at ")
11812 #?       (write-int32-hex-buffered Stderr %edi)
11813 #?       (write-buffered Stderr Newline)
11814 #?       (flush Stderr)
11815       89/<- *(eax+8) 1/r32/ecx  # Typeinfo-entry-index
11816       # ++curr-index
11817       ff 0/subop/increment *(ebp-4)
11818 $populate-mu-type:set-input-type:
11819       # r->input-var = v
11820       8b/-> *esi 1/r32/ecx
11821       89/<- *eax 1/r32/ecx  # Typeinfo-entry-input-var
11822       8b/-> *(esi+4) 1/r32/ecx
11823       89/<- *(eax+4) 1/r32/ecx  # Typeinfo-entry-input-var
11824       # restore line
11825       59/pop-to-ecx
11826       {
11827 $populate-mu-type:create-output-type:
11828         # if (r->output-var == 0) create a new var with some placeholder data
11829         81 7/subop/compare *(eax+0xc) 0/imm32  # Typeinfo-entry-output-var
11830         75/jump-if-!= break/disp8
11831         8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
11832         (new-literal Heap %edx %eax)
11833       }
11834       e9/jump loop/disp32
11835     }
11836 $populate-mu-type:invalidate-total-size-in-bytes:
11837     # Offsets and total size may not be accurate here since we may not yet
11838     # have encountered the element types.
11839     # We'll recompute them separately after parsing the entire program.
11840     c7 0/subop/copy *(edi+0xc) -2/imm32/uninitialized  # Typeinfo-total-size-in-bytes
11841 $populate-mu-type:end:
11842     # . reclaim locals
11843     81 0/subop/add %esp 0x224/imm32
11844     # . restore registers
11845     5f/pop-to-edi
11846     5e/pop-to-esi
11847     5b/pop-to-ebx
11848     5a/pop-to-edx
11849     59/pop-to-ecx
11850     58/pop-to-eax
11851     # reclaim curr-index
11852     81 0/subop/add %esp 4/imm32
11853     # . epilogue
11854     89/<- %esp 5/r32/ebp
11855     5d/pop-to-ebp
11856     c3/return
11857 
11858 $populate-mu-type:error1:
11859     # error("incomplete type definition '" t->name "'\n")
11860     (write-buffered *(ebp+0x10) "incomplete type definition '")
11861     (type-name *edi)  # Typeinfo-id => eax
11862     (write-buffered *(ebp+0x10) %eax)
11863     (write-buffered *(ebp+0x10) "\n")
11864     (flush *(ebp+0x10))
11865     (stop *(ebp+0x14) 1)
11866     # never gets here
11867 
11868 $populate-mu-type:error2:
11869     (write-buffered *(ebp+0x10) "type ")
11870     (type-name *edi)  # Typeinfo-id => eax
11871     (write-buffered *(ebp+0x10) %eax)
11872     (write-buffered *(ebp+0x10) ": 'addr' elements not allowed\n")
11873     (flush *(ebp+0x10))
11874     (stop *(ebp+0x14) 1)
11875     # never gets here
11876 
11877 $populate-mu-type:error3:
11878     (write-buffered *(ebp+0x10) "type ")
11879     (type-name *edi)  # Typeinfo-id => eax
11880     (write-buffered *(ebp+0x10) %eax)
11881     (write-buffered *(ebp+0x10) ": 'array' elements not allowed for now\n")
11882     (flush *(ebp+0x10))
11883     (stop *(ebp+0x14) 1)
11884     # never gets here
11885 
11886 $populate-mu-type:error4:
11887     (write-buffered *(ebp+0x10) "type ")
11888     (type-name *edi)  # Typeinfo-id => eax
11889     (write-buffered *(ebp+0x10) %eax)
11890     (write-buffered *(ebp+0x10) ": 'byte' elements not allowed\n")
11891     (flush *(ebp+0x10))
11892     (stop *(ebp+0x14) 1)
11893     # never gets here
11894 
11895 $populate-mu-type:error5:
11896     (write-buffered *(ebp+0x10) "type ")
11897     (type-name *edi)  # Typeinfo-id => eax
11898     (write-buffered *(ebp+0x10) %eax)
11899     (write-buffered *(ebp+0x10) ": 'slice' elements not allowed\n")
11900     (flush *(ebp+0x10))
11901     (stop *(ebp+0x14) 1)
11902     # never gets here
11903 
11904 $populate-mu-type:error6:
11905     (write-buffered *(ebp+0x10) "type ")
11906     (type-name *edi)  # Typeinfo-id => eax
11907     (write-buffered *(ebp+0x10) %eax)
11908     (write-buffered *(ebp+0x10) ": 'stream' elements not allowed for now\n")
11909     (flush *(ebp+0x10))
11910     (stop *(ebp+0x14) 1)
11911     # never gets here
11912 
11913 type-name:  # index: int -> result/eax: (addr array byte)
11914     # . prologue
11915     55/push-ebp
11916     89/<- %ebp 4/r32/esp
11917     #
11918     (index Type-id *(ebp+8))
11919 $type-name:end:
11920     # . epilogue
11921     89/<- %esp 5/r32/ebp
11922     5d/pop-to-ebp
11923     c3/return
11924 
11925 index:  # arr: (addr stream (handle array byte)), index: int -> result/eax: (addr array byte)
11926     # . prologue
11927     55/push-ebp
11928     89/<- %ebp 4/r32/esp
11929     # . save registers
11930     56/push-esi
11931     # TODO: bounds-check index
11932     # esi = arr
11933     8b/-> *(ebp+8) 6/r32/esi
11934     # eax = index
11935     8b/-> *(ebp+0xc) 0/r32/eax
11936     # eax = *(arr + 12 + index)
11937     8b/-> *(esi+eax<<2+0xc) 0/r32/eax
11938 $index:end:
11939     # . restore registers
11940     5e/pop-to-esi
11941     # . epilogue
11942     89/<- %esp 5/r32/ebp
11943     5d/pop-to-ebp
11944     c3/return
11945 
11946 #######################################################
11947 # Compute type sizes
11948 #######################################################
11949 
11950 # Compute the sizes of all user-defined types.
11951 # We'll need the sizes of their elements, which may be other user-defined
11952 # types, which we will compute as needed.
11953 
11954 # Initially, all user-defined types have their sizes set to -2 (invalid)
11955 populate-mu-type-sizes:  # err: (addr buffered-file), ed: (addr exit-descriptor)
11956     # . prologue
11957     55/push-ebp
11958     89/<- %ebp 4/r32/esp
11959 $populate-mu-type-sizes:total-sizes:
11960     # var curr/eax: (addr typeinfo) = lookup(Program->types)
11961     (lookup *_Program-types *_Program-types->payload)  # => eax
11962     {
11963       # if (curr == null) break
11964       3d/compare-eax-and 0/imm32/null
11965       74/jump-if-= break/disp8
11966       (populate-mu-type-sizes-in-type %eax *(ebp+8) *(ebp+0xc))
11967       # curr = lookup(curr->next)
11968       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
11969       eb/jump loop/disp8
11970     }
11971 $populate-mu-type-sizes:offsets:
11972     # curr = *Program->types
11973     (lookup *_Program-types *_Program-types->payload)  # => eax
11974     {
11975       # if (curr == null) break
11976       3d/compare-eax-and 0/imm32/null
11977       74/jump-if-= break/disp8
11978       (populate-mu-type-offsets %eax *(ebp+8) *(ebp+0xc))
11979       # curr = curr->next
11980       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
11981       eb/jump loop/disp8
11982     }
11983 $populate-mu-type-sizes:end:
11984     # . epilogue
11985     89/<- %esp 5/r32/ebp
11986     5d/pop-to-ebp
11987     c3/return
11988 
11989 # compute sizes of all fields, recursing as necessary
11990 # sum up all their sizes to arrive at total size
11991 # fields may be out of order, but that doesn't affect the answer
11992 populate-mu-type-sizes-in-type:  # T: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
11993     # . prologue
11994     55/push-ebp
11995     89/<- %ebp 4/r32/esp
11996     # . save registers
11997     50/push-eax
11998     51/push-ecx
11999     52/push-edx
12000     56/push-esi
12001     57/push-edi
12002     # esi = T
12003     8b/-> *(ebp+8) 6/r32/esi
12004     # if T is already computed, return
12005     81 7/subop/compare *(esi+0xc) 0/imm32  # Typeinfo-total-size-in-bytes
12006     0f 8d/jump-if->= $populate-mu-type-sizes-in-type:end/disp32
12007     # if T is being computed, abort
12008     81 7/subop/compare *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
12009     0f 84/jump-if-= $populate-mu-type-sizes-in-type:abort/disp32
12010     # tag T (-2 to -1) to avoid infinite recursion
12011     c7 0/subop/copy *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
12012     # var total-size/edi: int = 0
12013     bf/copy-to-edi 0/imm32
12014     # - for every field, if it's a user-defined type, compute its size
12015     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
12016     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
12017     89/<- %ecx 0/r32/eax
12018     # var table-size/edx: int = table->write
12019     8b/-> *ecx 2/r32/edx  # stream-write
12020     # var curr/ecx: (addr table_row) = table->data
12021     8d/copy-address *(ecx+0xc) 1/r32/ecx
12022     # var max/edx: (addr table_row) = table->data + table->write
12023     8d/copy-address *(ecx+edx) 2/r32/edx
12024     {
12025 $populate-mu-type-sizes-in-type:loop:
12026       # if (curr >= max) break
12027       39/compare %ecx 2/r32/edx
12028       73/jump-if-addr>= break/disp8
12029       # var t/eax: (addr typeinfo-entry) = lookup(curr->value)
12030       (lookup *(ecx+8) *(ecx+0xc))  # => eax
12031       # if (t->input-var == 0) silently ignore it; we'll emit a nice error message while type-checking
12032       81 7/subop/compare *eax 0/imm32  # Typeinfo-entry-input-var
12033       74/jump-if-= $populate-mu-type-sizes-in-type:end/disp8
12034       # compute size of t->input-var
12035       (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
12036       (compute-size-of-var %eax *(ebp+0xc) *(ebp+0x10))  # => eax
12037       # result += eax
12038       01/add-to %edi 0/r32/eax
12039       # curr += row-size
12040       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
12041       #
12042       eb/jump loop/disp8
12043     }
12044     # - save result
12045     89/<- *(esi+0xc) 7/r32/edi  # Typeinfo-total-size-in-bytes
12046 $populate-mu-type-sizes-in-type:end:
12047     # . restore registers
12048     5f/pop-to-edi
12049     5e/pop-to-esi
12050     5a/pop-to-edx
12051     59/pop-to-ecx
12052     58/pop-to-eax
12053     # . epilogue
12054     89/<- %esp 5/r32/ebp
12055     5d/pop-to-ebp
12056     c3/return
12057 
12058 $populate-mu-type-sizes-in-type:abort:
12059     (write-buffered *(ebp+0xc) "cycle in type definitions\n")
12060     (flush *(ebp+0xc))
12061     (stop *(ebp+0x10) 1)
12062     # never gets here
12063 
12064 # Analogous to size-of, except we need to compute what size-of can just read
12065 # off the right data structures.
12066 compute-size-of-var:  # in: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
12067     # . prologue
12068     55/push-ebp
12069     89/<- %ebp 4/r32/esp
12070     # . push registers
12071     51/push-ecx
12072     # var t/ecx: (addr type-tree) = lookup(v->type)
12073     8b/-> *(ebp+8) 1/r32/ecx
12074     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
12075     89/<- %ecx 0/r32/eax
12076     # if (t->is-atom == false) t = lookup(t->left)
12077     {
12078       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
12079       75/jump-if-!= break/disp8
12080       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
12081       89/<- %ecx 0/r32/eax
12082     }
12083     # TODO: ensure t is an atom
12084     (compute-size-of-type-id *(ecx+4) *(ebp+0xc) *(ebp+0x10))  # Type-tree-value => eax
12085 $compute-size-of-var:end:
12086     # . restore registers
12087     59/pop-to-ecx
12088     # . epilogue
12089     89/<- %esp 5/r32/ebp
12090     5d/pop-to-ebp
12091     c3/return
12092 
12093 compute-size-of-type-id:  # t: type-id, err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
12094     # . prologue
12095     55/push-ebp
12096     89/<- %ebp 4/r32/esp
12097     # . save registers
12098     51/push-ecx
12099     # var out/ecx: (handle typeinfo)
12100     68/push 0/imm32
12101     68/push 0/imm32
12102     89/<- %ecx 4/r32/esp
12103     # eax = t
12104     8b/-> *(ebp+8) 0/r32/eax
12105     # if t is a literal, return 0
12106     3d/compare-eax-and 0/imm32/literal
12107     0f 84/jump-if-= $compute-size-of-type-id:end/disp32  # eax changes type from type-id to int
12108     # if t is a byte, return 4 (because we don't really support non-multiples of 4)
12109     3d/compare-eax-and 8/imm32/byte
12110     {
12111       75/jump-if-!= break/disp8
12112       b8/copy-to-eax 4/imm32
12113       eb/jump $compute-size-of-type-id:end/disp8
12114     }
12115     # if t is a handle, return 8
12116     3d/compare-eax-and 4/imm32/handle
12117     {
12118       75/jump-if-!= break/disp8
12119       b8/copy-to-eax 8/imm32
12120       eb/jump $compute-size-of-type-id:end/disp8  # eax changes type from type-id to int
12121     }
12122     # if t is a slice, return 8
12123     3d/compare-eax-and 0xc/imm32/slice
12124     {
12125       75/jump-if-!= break/disp8
12126       b8/copy-to-eax 8/imm32
12127       eb/jump $compute-size-of-type-id:end/disp8  # eax changes type from type-id to int
12128     }
12129     # if t is a user-defined type, compute its size
12130     # TODO: support non-atom type
12131     (find-typeinfo %eax %ecx)
12132     {
12133       81 7/subop/compare *ecx 0/imm32
12134       74/jump-if-= break/disp8
12135 $compute-size-of-type-id:user-defined:
12136       (lookup *ecx *(ecx+4))  # => eax
12137       (populate-mu-type-sizes-in-type %eax *(ebp+0xc) *(ebp+0x10))
12138       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
12139       eb/jump $compute-size-of-type-id:end/disp8
12140     }
12141     # otherwise return the word size
12142     b8/copy-to-eax 4/imm32
12143 $compute-size-of-type-id:end:
12144     # . reclaim locals
12145     81 0/subop/add %esp 8/imm32
12146     # . restore registers
12147     59/pop-to-ecx
12148     # . epilogue
12149     89/<- %esp 5/r32/ebp
12150     5d/pop-to-ebp
12151     c3/return
12152 
12153 # at this point we have total sizes for all user-defined types
12154 # compute offsets for each element
12155 # complication: fields may be out of order
12156 populate-mu-type-offsets:  # in: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
12157     # . prologue
12158     55/push-ebp
12159     89/<- %ebp 4/r32/esp
12160     # . save registers
12161     50/push-eax
12162     51/push-ecx
12163     52/push-edx
12164     53/push-ebx
12165     56/push-esi
12166     57/push-edi
12167 #?     (dump-typeinfos "aaa\n")
12168     # var curr-offset/edi: int = 0
12169     bf/copy-to-edi 0/imm32
12170     # var table/ecx: (addr table string_key (handle typeinfo-entry)) = lookup(in->fields)
12171     8b/-> *(ebp+8) 1/r32/ecx
12172     (lookup *(ecx+4) *(ecx+8))  # Typeinfo-fields Typeinfo-fields => eax
12173     89/<- %ecx 0/r32/eax
12174     # var num-elems/edx: int = table->write / Typeinfo-fields-row-size
12175     8b/-> *ecx 2/r32/edx  # stream-write
12176     c1 5/subop/shift-right-logical  %edx 4/imm8
12177     # var i/ebx: int = 0
12178     bb/copy-to-ebx 0/imm32
12179     {
12180 $populate-mu-type-offsets:loop:
12181       39/compare %ebx 2/r32/edx
12182       0f 8d/jump-if->= break/disp32
12183 #?       (write-buffered Stderr "looking up index ")
12184 #?       (write-int32-hex-buffered Stderr %ebx)
12185 #?       (write-buffered Stderr " in ")
12186 #?       (write-int32-hex-buffered Stderr *(ebp+8))
12187 #?       (write-buffered Stderr Newline)
12188 #?       (flush Stderr)
12189       # var v/esi: (addr typeinfo-entry)
12190       (locate-typeinfo-entry-with-index %ecx %ebx *(ebp+0xc) *(ebp+0x10))  # => eax
12191       89/<- %esi 0/r32/eax
12192       # if v is null, silently move on; we'll emit a nice error message while type-checking
12193       81 7/subop/compare %esi 0/imm32  # Typeinfo-entry-input-var
12194       74/jump-if-= $populate-mu-type-offsets:end/disp8
12195       # if (v->input-var == 0) silently ignore v; we'll emit a nice error message while type-checking
12196       81 7/subop/compare *esi 0/imm32  # Typeinfo-entry-input-var
12197       74/jump-if-= $populate-mu-type-offsets:end/disp8
12198       # v->output-var->offset = curr-offset
12199       # . eax: (addr var)
12200       (lookup *(esi+0xc) *(esi+0x10))  # Typeinfo-entry-output-var Typeinfo-entry-output-var => eax
12201       89/<- *(eax+0x14) 7/r32/edi  # Var-offset
12202       # curr-offset += size-of(v->input-var)
12203       (lookup *esi *(esi+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
12204       (size-of %eax)  # => eax
12205       01/add-to %edi 0/r32/eax
12206       # ++i
12207       43/increment-ebx
12208       e9/jump loop/disp32
12209     }
12210 $populate-mu-type-offsets:end:
12211     # . restore registers
12212     5f/pop-to-edi
12213     5e/pop-to-esi
12214     5b/pop-to-ebx
12215     5a/pop-to-edx
12216     59/pop-to-ecx
12217     58/pop-to-eax
12218     # . epilogue
12219     89/<- %esp 5/r32/ebp
12220     5d/pop-to-ebp
12221     c3/return
12222 
12223 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)
12224     # . prologue
12225     55/push-ebp
12226     89/<- %ebp 4/r32/esp
12227     # . save registers
12228     51/push-ecx
12229     52/push-edx
12230     53/push-ebx
12231     56/push-esi
12232     57/push-edi
12233     # esi = table
12234     8b/-> *(ebp+8) 6/r32/esi
12235     # var curr/ecx: (addr row (handle array byte) (handle typeinfo-entry)) = table->data
12236     8d/copy-address *(esi+0xc) 1/r32/ecx
12237     # var max/edx: (addr byte) = &table->data[table->write]
12238     8b/-> *esi 2/r32/edx
12239     8d/copy-address *(ecx+edx) 2/r32/edx
12240     {
12241 $locate-typeinfo-entry-with-index:loop:
12242       39/compare %ecx 2/r32/edx
12243       73/jump-if-addr>= break/disp8
12244       # var v/eax: (addr typeinfo-entry)
12245       (lookup *(ecx+8) *(ecx+0xc))  # => eax
12246       # if (v->index == idx) return v
12247       8b/-> *(eax+8) 3/r32/ebx  # Typeinfo-entry-index
12248 #?       (write-buffered Stderr "comparing ")
12249 #?       (write-int32-hex-buffered Stderr %ebx)
12250 #?       (write-buffered Stderr " and ")
12251 #?       (write-int32-hex-buffered Stderr *(ebp+0xc))
12252 #?       (write-buffered Stderr Newline)
12253 #?       (flush Stderr)
12254       39/compare *(ebp+0xc) 3/r32/ebx
12255       74/jump-if-= $locate-typeinfo-entry-with-index:end/disp8
12256       # curr += Typeinfo-entry-size
12257       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-entry-size
12258       #
12259       eb/jump loop/disp8
12260     }
12261     # return 0
12262     b8/copy-to-eax 0/imm32
12263 $locate-typeinfo-entry-with-index:end:
12264 #?     (write-buffered Stderr "returning ")
12265 #?     (write-int32-hex-buffered Stderr %eax)
12266 #?     (write-buffered Stderr Newline)
12267 #?     (flush Stderr)
12268     # . restore registers
12269     5f/pop-to-edi
12270     5e/pop-to-esi
12271     5b/pop-to-ebx
12272     5a/pop-to-edx
12273     59/pop-to-ecx
12274     # . epilogue
12275     89/<- %esp 5/r32/ebp
12276     5d/pop-to-ebp
12277     c3/return
12278 
12279 dump-typeinfos:  # hdr: (addr array byte)
12280     # . prologue
12281     55/push-ebp
12282     89/<- %ebp 4/r32/esp
12283     # . save registers
12284     50/push-eax
12285     #
12286     (write-buffered Stderr *(ebp+8))
12287     (flush Stderr)
12288     # var curr/eax: (addr typeinfo) = lookup(Program->types)
12289     (lookup *_Program-types *_Program-types->payload)  # => eax
12290     {
12291       # if (curr == null) break
12292       3d/compare-eax-and 0/imm32
12293       74/jump-if-= break/disp8
12294       (write-buffered Stderr "---\n")
12295       (flush Stderr)
12296       (dump-typeinfo %eax)
12297       # curr = lookup(curr->next)
12298       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
12299       eb/jump loop/disp8
12300     }
12301 $dump-typeinfos:end:
12302     # . restore registers
12303     58/pop-to-eax
12304     # . epilogue
12305     89/<- %esp 5/r32/ebp
12306     5d/pop-to-ebp
12307     c3/return
12308 
12309 dump-typeinfo:  # in: (addr typeinfo)
12310     # . prologue
12311     55/push-ebp
12312     89/<- %ebp 4/r32/esp
12313     # . save registers
12314     50/push-eax
12315     51/push-ecx
12316     52/push-edx
12317     53/push-ebx
12318     56/push-esi
12319     57/push-edi
12320     # esi = in
12321     8b/-> *(ebp+8) 6/r32/esi
12322     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
12323     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
12324     89/<- %ecx 0/r32/eax
12325     (write-buffered Stderr "id:")
12326     (write-int32-hex-buffered Stderr *esi)
12327     (write-buffered Stderr "\n")
12328     (write-buffered Stderr "fields @ ")
12329     (write-int32-hex-buffered Stderr %ecx)
12330     (write-buffered Stderr Newline)
12331     (flush Stderr)
12332     (write-buffered Stderr "  write: ")
12333     (write-int32-hex-buffered Stderr *ecx)
12334     (write-buffered Stderr Newline)
12335     (flush Stderr)
12336     (write-buffered Stderr "  read: ")
12337     (write-int32-hex-buffered Stderr *(ecx+4))
12338     (write-buffered Stderr Newline)
12339     (flush Stderr)
12340     (write-buffered Stderr "  size: ")
12341     (write-int32-hex-buffered Stderr *(ecx+8))
12342     (write-buffered Stderr Newline)
12343     (flush Stderr)
12344     # var table-size/edx: int = table->write
12345     8b/-> *ecx 2/r32/edx  # stream-write
12346     # var curr/ecx: (addr table_row) = table->data
12347     8d/copy-address *(ecx+0xc) 1/r32/ecx
12348     # var max/edx: (addr table_row) = table->data + table->write
12349     8d/copy-address *(ecx+edx) 2/r32/edx
12350     {
12351 $dump-typeinfo:loop:
12352       # if (curr >= max) break
12353       39/compare %ecx 2/r32/edx
12354       0f 83/jump-if-addr>= break/disp32
12355       (write-buffered Stderr "  row:\n")
12356       (write-buffered Stderr "    key: ")
12357       (write-int32-hex-buffered Stderr *ecx)
12358       (write-buffered Stderr ",")
12359       (write-int32-hex-buffered Stderr *(ecx+4))
12360       (write-buffered Stderr " = '")
12361       (lookup *ecx *(ecx+4))
12362       (write-buffered Stderr %eax)
12363       (write-buffered Stderr "' @ ")
12364       (write-int32-hex-buffered Stderr %eax)
12365       (write-buffered Stderr Newline)
12366       (flush Stderr)
12367       (write-buffered Stderr "    value: ")
12368       (write-int32-hex-buffered Stderr *(ecx+8))
12369       (write-buffered Stderr ",")
12370       (write-int32-hex-buffered Stderr *(ecx+0xc))
12371       (write-buffered Stderr " = typeinfo-entry@")
12372       (lookup *(ecx+8) *(ecx+0xc))
12373       (write-int32-hex-buffered Stderr %eax)
12374       (write-buffered Stderr Newline)
12375       (flush Stderr)
12376       (write-buffered Stderr "        input var@")
12377       (dump-var 5 %eax)
12378       (lookup *(ecx+8) *(ecx+0xc))
12379       (write-buffered Stderr "        index: ")
12380       (write-int32-hex-buffered Stderr *(eax+8))
12381       (write-buffered Stderr Newline)
12382       (flush Stderr)
12383       (write-buffered Stderr "        output var@")
12384       8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
12385       (dump-var 5 %eax)
12386       (flush Stderr)
12387       # curr += row-size
12388       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
12389       #
12390       e9/jump loop/disp32
12391     }
12392 $dump-typeinfo:end:
12393     # . restore registers
12394     5f/pop-to-edi
12395     5e/pop-to-esi
12396     5b/pop-to-ebx
12397     5a/pop-to-edx
12398     59/pop-to-ecx
12399     58/pop-to-eax
12400     # . epilogue
12401     89/<- %esp 5/r32/ebp
12402     5d/pop-to-ebp
12403     c3/return
12404 
12405 dump-var:  # indent: int, v: (addr handle var)
12406     # . prologue
12407     55/push-ebp
12408     89/<- %ebp 4/r32/esp
12409     # . save registers
12410     50/push-eax
12411     53/push-ebx
12412     # eax = v
12413     8b/-> *(ebp+0xc) 0/r32/eax
12414     #
12415     (write-int32-hex-buffered Stderr *eax)
12416     (write-buffered Stderr ",")
12417     (write-int32-hex-buffered Stderr *(eax+4))
12418     (write-buffered Stderr "->")
12419     (lookup *eax *(eax+4))
12420     (write-int32-hex-buffered Stderr %eax)
12421     (write-buffered Stderr Newline)
12422     (flush Stderr)
12423     {
12424       3d/compare-eax-and 0/imm32
12425       0f 84/jump-if-= break/disp32
12426       (emit-indent Stderr *(ebp+8))
12427       (write-buffered Stderr "name: ")
12428       89/<- %ebx 0/r32/eax
12429       (write-int32-hex-buffered Stderr *ebx)  # Var-name
12430       (write-buffered Stderr ",")
12431       (write-int32-hex-buffered Stderr *(ebx+4))  # Var-name
12432       (write-buffered Stderr "->")
12433       (lookup *ebx *(ebx+4))  # Var-name
12434       (write-int32-hex-buffered Stderr %eax)
12435       {
12436         3d/compare-eax-and 0/imm32
12437         74/jump-if-= break/disp8
12438         (write-buffered Stderr Space)
12439         (write-buffered Stderr %eax)
12440       }
12441       (write-buffered Stderr Newline)
12442       (flush Stderr)
12443       (emit-indent Stderr *(ebp+8))
12444       (write-buffered Stderr "block depth: ")
12445       (write-int32-hex-buffered Stderr *(ebx+0x10))  # Var-block-depth
12446       (write-buffered Stderr Newline)
12447       (flush Stderr)
12448       (emit-indent Stderr *(ebp+8))
12449       (write-buffered Stderr "stack offset: ")
12450       (write-int32-hex-buffered Stderr *(ebx+0x14))  # Var-offset
12451       (write-buffered Stderr Newline)
12452       (flush Stderr)
12453       (emit-indent Stderr *(ebp+8))
12454       (write-buffered Stderr "reg: ")
12455       (write-int32-hex-buffered Stderr *(ebx+0x18))  # Var-register
12456       (write-buffered Stderr ",")
12457       (write-int32-hex-buffered Stderr *(ebx+0x1c))  # Var-register
12458       (write-buffered Stderr "->")
12459       (flush Stderr)
12460       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register
12461       (write-int32-hex-buffered Stderr %eax)
12462       {
12463         3d/compare-eax-and 0/imm32
12464         74/jump-if-= break/disp8
12465         (write-buffered Stderr Space)
12466         (write-buffered Stderr %eax)
12467       }
12468       (write-buffered Stderr Newline)
12469       (flush Stderr)
12470     }
12471 $dump-var:end:
12472     # . restore registers
12473     5b/pop-to-ebx
12474     58/pop-to-eax
12475     # . epilogue
12476     89/<- %esp 5/r32/ebp
12477     5d/pop-to-ebp
12478     c3/return
12479 
12480 #######################################################
12481 # Type-checking
12482 #######################################################
12483 
12484 check-mu-types:  # err: (addr buffered-file), ed: (addr exit-descriptor)
12485     # . prologue
12486     55/push-ebp
12487     89/<- %ebp 4/r32/esp
12488     # . save registers
12489     50/push-eax
12490     # var curr/eax: (addr function) = lookup(Program->functions)
12491     (lookup *_Program-functions *_Program-functions->payload)  # => eax
12492     {
12493 $check-mu-types:loop:
12494       # if (curr == null) break
12495       3d/compare-eax-and 0/imm32
12496       0f 84/jump-if-= break/disp32
12497 +--  8 lines: #?       # dump curr->name ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
12505       (check-mu-function %eax *(ebp+8) *(ebp+0xc))
12506       # curr = lookup(curr->next)
12507       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
12508       e9/jump loop/disp32
12509     }
12510 $check-mu-types:end:
12511     # . restore registers
12512     58/pop-to-eax
12513     # . epilogue
12514     89/<- %esp 5/r32/ebp
12515     5d/pop-to-ebp
12516     c3/return
12517 
12518 check-mu-function:  # fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12519     # . prologue
12520     55/push-ebp
12521     89/<- %ebp 4/r32/esp
12522     # . save registers
12523     50/push-eax
12524     # eax = f
12525     8b/-> *(ebp+8) 0/r32/eax
12526     # TODO: anything to check in header?
12527     # var body/eax: (addr block) = lookup(f->body)
12528     (lookup *(eax+0x18) *(eax+0x1c))  # Function-body Function-body => eax
12529     (check-mu-block %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10))
12530 $check-mu-function:end:
12531     # . restore registers
12532     58/pop-to-eax
12533     # . epilogue
12534     89/<- %esp 5/r32/ebp
12535     5d/pop-to-ebp
12536     c3/return
12537 
12538 check-mu-block:  # block: (addr block), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12539     # . prologue
12540     55/push-ebp
12541     89/<- %ebp 4/r32/esp
12542     # . save registers
12543     50/push-eax
12544     # eax = block
12545     8b/-> *(ebp+8) 0/r32/eax
12546     # var stmts/eax: (addr list stmt) = lookup(block->statements)
12547     (lookup *(eax+4) *(eax+8))  # Block-stmts Block-stmts => eax
12548     #
12549     {
12550 $check-mu-block:check-empty:
12551       3d/compare-eax-and 0/imm32
12552       0f 84/jump-if-= break/disp32
12553       # emit block->statements
12554       (check-mu-stmt-list %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12555     }
12556 $check-mu-block:end:
12557     # . restore registers
12558     58/pop-to-eax
12559     # . epilogue
12560     89/<- %esp 5/r32/ebp
12561     5d/pop-to-ebp
12562     c3/return
12563 
12564 check-mu-stmt-list:  # stmts: (addr list stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12565     # . prologue
12566     55/push-ebp
12567     89/<- %ebp 4/r32/esp
12568     # . save registers
12569     50/push-eax
12570     56/push-esi
12571     # esi = stmts
12572     8b/-> *(ebp+8) 6/r32/esi
12573     {
12574 $check-mu-stmt-list:loop:
12575       81 7/subop/compare %esi 0/imm32
12576       0f 84/jump-if-= break/disp32
12577       # var curr-stmt/eax: (addr stmt) = lookup(stmts->value)
12578       (lookup *esi *(esi+4))  # List-value List-value => eax
12579       {
12580 $check-mu-stmt-list:check-for-block:
12581         81 7/subop/compare *eax 0/imm32/block  # Stmt-tag
12582         75/jump-if-!= break/disp8
12583 $check-mu-stmt-list:block:
12584         (check-mu-block %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12585         eb/jump $check-mu-stmt-list:continue/disp8
12586       }
12587       {
12588 $check-mu-stmt-list:check-for-stmt1:
12589         81 7/subop/compare *eax 1/imm32/stmt1  # Stmt-tag
12590         0f 85/jump-if-!= break/disp32
12591 $check-mu-stmt-list:stmt1:
12592         (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12593         eb/jump $check-mu-stmt-list:continue/disp8
12594       }
12595       {
12596 $check-mu-stmt-list:check-for-reg-var-def:
12597         81 7/subop/compare *eax 3/imm32/reg-var-def  # Stmt-tag
12598         0f 85/jump-if-!= break/disp32
12599 $check-mu-stmt-list:reg-var-def:
12600         (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12601         eb/jump $check-mu-stmt-list:continue/disp8
12602       }
12603 $check-mu-stmt-list:continue:
12604       # TODO: raise an error on unrecognized Stmt-tag
12605       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
12606       89/<- %esi 0/r32/eax
12607       e9/jump loop/disp32
12608     }
12609 $check-mu-stmt-list:end:
12610     # . restore registers
12611     5e/pop-to-esi
12612     58/pop-to-eax
12613     # . epilogue
12614     89/<- %esp 5/r32/ebp
12615     5d/pop-to-ebp
12616     c3/return
12617 
12618 check-mu-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12619     # . prologue
12620     55/push-ebp
12621     89/<- %ebp 4/r32/esp
12622     # . save registers
12623     50/push-eax
12624     # - if stmt's operation matches a primitive, check against it
12625     (has-primitive-name? *(ebp+8))  # => eax
12626     3d/compare-eax-and 0/imm32/false
12627     {
12628       74/jump-if-= break/disp8
12629       (check-mu-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12630       e9/jump $check-mu-stmt:end/disp32
12631     }
12632     # - otherwise find a function to check against
12633     # var f/eax: (addr function) = lookup(*Program->functions)
12634     (lookup *_Program-functions *_Program-functions->payload)  # => eax
12635     (find-matching-function %eax *(ebp+8))  # => eax
12636     3d/compare-eax-and 0/imm32
12637     {
12638       74/jump-if-= break/disp8
12639       (check-mu-call *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12640       eb/jump $check-mu-stmt:end/disp8
12641     }
12642     # var f/eax: (addr function) = lookup(*Program->signatures)
12643     (lookup *_Program-signatures *_Program-signatures->payload)  # => eax
12644     (find-matching-function %eax *(ebp+8))  # => eax
12645     3d/compare-eax-and 0/imm32
12646     {
12647       74/jump-if-= break/disp8
12648       (check-mu-call *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12649       eb/jump $check-mu-stmt:end/disp8
12650     }
12651     # - otherwise abort
12652     e9/jump $check-mu-stmt:unknown-call/disp32
12653 $check-mu-stmt:end:
12654     # . restore registers
12655     58/pop-to-eax
12656     # . epilogue
12657     89/<- %esp 5/r32/ebp
12658     5d/pop-to-ebp
12659     c3/return
12660 
12661 $check-mu-stmt:unknown-call:
12662     (write-buffered *(ebp+0x10) "unknown function '")
12663     8b/-> *(ebp+8) 0/r32/eax
12664     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
12665     (write-buffered *(ebp+0x10) %eax)
12666     (write-buffered *(ebp+0x10) "'\n")
12667     (flush *(ebp+0x10))
12668     (stop *(ebp+0x14) 1)
12669     # never gets here
12670 
12671 has-primitive-name?:  # stmt: (addr stmt) -> result/eax: boolean
12672     # . prologue
12673     55/push-ebp
12674     89/<- %ebp 4/r32/esp
12675     # . save registers
12676     51/push-ecx
12677     56/push-esi
12678     # var name/esi: (addr array byte) = lookup(stmt->operation)
12679     8b/-> *(ebp+8) 6/r32/esi
12680     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
12681     89/<- %esi 0/r32/eax
12682     # if (name == "get") return true
12683     (string-equal? %esi "get")  # => eax
12684     3d/compare-eax-and 0/imm32/false
12685     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12686     # if (name == "index") return true
12687     (string-equal? %esi "index")  # => eax
12688     3d/compare-eax-and 0/imm32/false
12689     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12690     # if (name == "length") return true
12691     (string-equal? %esi "length")  # => eax
12692     3d/compare-eax-and 0/imm32/false
12693     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12694     # if (name == "compute-offset") return true
12695     (string-equal? %esi "compute-offset")  # => eax
12696     3d/compare-eax-and 0/imm32/false
12697     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12698     # if (name == "copy-object") return true
12699     (string-equal? %esi "copy-object")  # => eax
12700     3d/compare-eax-and 0/imm32/false
12701     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12702     # if (name == "allocate") return true
12703     (string-equal? %esi "allocate")  # => eax
12704     3d/compare-eax-and 0/imm32/false
12705     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12706     # if (name == "populate") return true
12707     (string-equal? %esi "populate")  # => eax
12708     3d/compare-eax-and 0/imm32/false
12709     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12710     # if (name == "populate-stream") return true
12711     (string-equal? %esi "populate-stream")  # => eax
12712     3d/compare-eax-and 0/imm32/false
12713     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12714     # if (name == "read-from-stream") return true
12715     (string-equal? %esi "read-from-stream")  # => eax
12716     3d/compare-eax-and 0/imm32/false
12717     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12718     # if (name == "write-to-stream") return true
12719     (string-equal? %esi "write-to-stream")  # => eax
12720     3d/compare-eax-and 0/imm32/false
12721     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12722     # var curr/ecx: (addr primitive) = Primitives
12723     b9/copy-to-ecx Primitives/imm32
12724     {
12725 $has-primitive-name?:loop:
12726       # if (curr == null) break
12727       81 7/subop/compare %ecx 0/imm32
12728       74/jump-if-= break/disp8
12729       # if (primitive->name == name) return true
12730       (lookup *ecx *(ecx+4))  # Primitive-name Primitive-name => eax
12731       (string-equal? %esi %eax)  # => eax
12732       3d/compare-eax-and 0/imm32/false
12733       75/jump-if-!= $has-primitive-name?:end/disp8
12734 $has-primitive-name?:next-primitive:
12735       # curr = curr->next
12736       (lookup *(ecx+0x38) *(ecx+0x3c))  # Primitive-next Primitive-next => eax
12737       89/<- %ecx 0/r32/eax
12738       #
12739       e9/jump loop/disp32
12740     }
12741     # return null
12742     b8/copy-to-eax 0/imm32
12743 $has-primitive-name?:end:
12744     # . restore registers
12745     5e/pop-to-esi
12746     59/pop-to-ecx
12747     # . epilogue
12748     89/<- %esp 5/r32/ebp
12749     5d/pop-to-ebp
12750     c3/return
12751 
12752 check-mu-primitive:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12753     # . prologue
12754     55/push-ebp
12755     89/<- %ebp 4/r32/esp
12756     # . save registers
12757     50/push-eax
12758     51/push-ecx
12759     # var op/ecx: (addr array byte) = lookup(stmt->operation)
12760     8b/-> *(ebp+8) 0/r32/eax
12761     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
12762     89/<- %ecx 0/r32/eax
12763     # if (op == "copy") check-mu-copy-stmt
12764     {
12765       (string-equal? %ecx "copy")  # => eax
12766       3d/compare-eax-and 0/imm32/false
12767       74/jump-if-= break/disp8
12768       (check-mu-copy-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12769       e9/jump $check-mu-primitive:end/disp32
12770     }
12771     # if (op == "copy-to") check-mu-copy-to-stmt
12772     {
12773       (string-equal? %ecx "copy-to")  # => eax
12774       3d/compare-eax-and 0/imm32/false
12775       74/jump-if-= break/disp8
12776       (check-mu-copy-to-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12777       e9/jump $check-mu-primitive:end/disp32
12778     }
12779     # if (op == "compare") check-mu-compare-stmt
12780     {
12781       (string-equal? %ecx "compare")  # => eax
12782       3d/compare-eax-and 0/imm32/false
12783       74/jump-if-= break/disp8
12784       (check-mu-compare-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12785       e9/jump $check-mu-primitive:end/disp32
12786     }
12787     # if (op == "address") check-mu-address-stmt
12788     {
12789       (string-equal? %ecx "address")  # => eax
12790       3d/compare-eax-and 0/imm32/false
12791       74/jump-if-= break/disp8
12792       (check-mu-address-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12793       e9/jump $check-mu-primitive:end/disp32
12794     }
12795     # if (op == "get") check-mu-get-stmt
12796     {
12797       (string-equal? %ecx "get")  # => eax
12798       3d/compare-eax-and 0/imm32/false
12799       74/jump-if-= break/disp8
12800       (check-mu-get-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12801       e9/jump $check-mu-primitive:end/disp32
12802     }
12803     # if (op == "index") check-mu-index-stmt
12804     {
12805       (string-equal? %ecx "index")  # => eax
12806       3d/compare-eax-and 0/imm32/false
12807       74/jump-if-= break/disp8
12808       (check-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12809       e9/jump $check-mu-primitive:end/disp32
12810     }
12811     # if (op == "length") check-mu-length-stmt
12812     {
12813       (string-equal? %ecx "length")  # => eax
12814       3d/compare-eax-and 0/imm32/false
12815       74/jump-if-= break/disp8
12816       (check-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12817       e9/jump $check-mu-primitive:end/disp32
12818     }
12819     # if (op == "compute-offset") check-mu-compute-offset-stmt
12820     {
12821       (string-equal? %ecx "compute-offset")  # => eax
12822       3d/compare-eax-and 0/imm32/false
12823       74/jump-if-= break/disp8
12824       (check-mu-compute-offset-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12825       e9/jump $check-mu-primitive:end/disp32
12826     }
12827     # if (op == "copy-object") check-mu-copy-object-stmt
12828     {
12829       (string-equal? %ecx "copy-object")  # => eax
12830       3d/compare-eax-and 0/imm32/false
12831       74/jump-if-= break/disp8
12832       (check-mu-copy-object-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12833       e9/jump $check-mu-primitive:end/disp32
12834     }
12835     # if (op == "allocate") check-mu-allocate-stmt
12836     {
12837       (string-equal? %ecx "allocate")  # => eax
12838       3d/compare-eax-and 0/imm32/false
12839       74/jump-if-= break/disp8
12840       (check-mu-allocate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12841       e9/jump $check-mu-primitive:end/disp32
12842     }
12843     # if (op == "populate") check-mu-populate-stmt
12844     {
12845       (string-equal? %ecx "populate")  # => eax
12846       3d/compare-eax-and 0/imm32/false
12847       74/jump-if-= break/disp8
12848       (check-mu-populate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12849       e9/jump $check-mu-primitive:end/disp32
12850     }
12851     # if (op == "populate-stream") check-mu-populate-stream-stmt
12852     {
12853       (string-equal? %ecx "populate-stream")  # => eax
12854       3d/compare-eax-and 0/imm32/false
12855       74/jump-if-= break/disp8
12856       (check-mu-populate-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12857       e9/jump $check-mu-primitive:end/disp32
12858     }
12859     # if (op == "read-from-stream") check-mu-read-from-stream-stmt
12860     {
12861       (string-equal? %ecx "read-from-stream")  # => eax
12862       3d/compare-eax-and 0/imm32/false
12863       74/jump-if-= break/disp8
12864       (check-mu-read-from-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12865       e9/jump $check-mu-primitive:end/disp32
12866     }
12867     # if (op == "write-to-stream") check-mu-write-to-stream-stmt
12868     {
12869       (string-equal? %ecx "write-to-stream")  # => eax
12870       3d/compare-eax-and 0/imm32/false
12871       74/jump-if-= break/disp8
12872       (check-mu-write-to-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12873       e9/jump $check-mu-primitive:end/disp32
12874     }
12875     # otherwise check-numberlike-stmt
12876     (check-mu-numberlike-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12877 $check-mu-primitive:end:
12878     # . restore registers
12879     59/pop-to-ecx
12880     58/pop-to-eax
12881     # . epilogue
12882     89/<- %esp 5/r32/ebp
12883     5d/pop-to-ebp
12884     c3/return
12885 
12886 # by default, Mu primitives should only operate on 'number-like' types
12887 check-mu-numberlike-primitive:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12888     # . prologue
12889     55/push-ebp
12890     89/<- %ebp 4/r32/esp
12891     # . save registers
12892     50/push-eax
12893     51/push-ecx
12894     56/push-esi
12895     # esi = stmt
12896     8b/-> *(ebp+8) 6/r32/esi
12897     # var gas/ecx: int = 2
12898     b9/copy-to-ecx 2/imm32
12899     # - check at most 1 output
12900     # var output/eax: (addr stmt-var) = stmt->outputs
12901     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
12902     {
12903       3d/compare-eax-and 0/imm32
12904       74/jump-if-= break/disp8
12905 $check-mu-numberlike-primitive:output:
12906       (check-mu-numberlike-output %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12907       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
12908       3d/compare-eax-and 0/imm32
12909       0f 85/jump-if-!= $check-mu-numberlike-primitive:error-too-many-outputs/disp32
12910       # check output is in a register
12911       # --gas
12912       49/decrement-ecx
12913     }
12914     # - check first inout
12915     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12916     {
12917       3d/compare-eax-and 0/imm32
12918       0f 84/jump-if-= $check-mu-numberlike-primitive:end/disp32
12919 $check-mu-numberlike-primitive:first-inout:
12920       (check-mu-numberlike-arg %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12921       # --gas
12922       49/decrement-ecx
12923     }
12924     # - check second inout
12925     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
12926     {
12927       3d/compare-eax-and 0/imm32
12928       74/jump-if-= $check-mu-numberlike-primitive:end/disp8
12929 $check-mu-numberlike-primitive:second-inout:
12930       # is a second inout allowed?
12931       81 7/subop/compare %ecx 0/imm32
12932       0f 84/jump-if-= $check-mu-numberlike-primitive:error-too-many-inouts/disp32
12933 $check-mu-numberlike-primitive:second-inout-permitted:
12934       (check-mu-numberlike-arg %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12935     }
12936 $check-mu-numberlike-primitive:third-inout:
12937     # if there's a third arg, raise an error
12938     81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
12939     0f 85/jump-if-!= $check-mu-numberlike-primitive:error-too-many-inouts/disp32
12940 $check-mu-numberlike-primitive:end:
12941     # . restore registers
12942     5e/pop-to-esi
12943     59/pop-to-ecx
12944     58/pop-to-eax
12945     # . epilogue
12946     89/<- %esp 5/r32/ebp
12947     5d/pop-to-ebp
12948     c3/return
12949 
12950 $check-mu-numberlike-primitive:error-too-many-inouts:
12951     (write-buffered *(ebp+0x10) "fn ")
12952     8b/-> *(ebp+0xc) 0/r32/eax
12953     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12954     (write-buffered *(ebp+0x10) %eax)
12955     (write-buffered *(ebp+0x10) ": stmt ")
12956     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
12957     (write-buffered *(ebp+0x10) %eax)
12958     (write-buffered *(ebp+0x10) ": too many inouts; most primitives support at most two arguments, across inouts and outputs\n")
12959     (flush *(ebp+0x10))
12960     (stop *(ebp+0x14) 1)
12961     # never gets here
12962 
12963 $check-mu-numberlike-primitive:error-too-many-outputs:
12964     (write-buffered *(ebp+0x10) "fn ")
12965     8b/-> *(ebp+0xc) 0/r32/eax
12966     (lookup *eax *(eax+4))  # Function-name Function-name => eax
12967     (write-buffered *(ebp+0x10) %eax)
12968     (write-buffered *(ebp+0x10) ": stmt ")
12969     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
12970     (write-buffered *(ebp+0x10) %eax)
12971     (write-buffered *(ebp+0x10) ": too many outputs; most primitives support at most one output\n")
12972     (flush *(ebp+0x10))
12973     (stop *(ebp+0x14) 1)
12974     # never gets here
12975 
12976 check-mu-numberlike-arg:  # v: (addr stmt-var), stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12977     # . prologue
12978     55/push-ebp
12979     89/<- %ebp 4/r32/esp
12980     # . save registers
12981     50/push-eax
12982     56/push-esi
12983     # var t/esi: (addr type-tree) = lookup(v->value->type)
12984     8b/-> *(ebp+8) 0/r32/eax
12985     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12986     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12987     89/<- %esi 0/r32/eax
12988 $check-mu-numberlike-arg:check-literal:
12989     # if t is an int, return
12990     (is-simple-mu-type? %esi 0)  # literal => eax
12991     3d/compare-eax-and 0/imm32/false
12992     75/jump-if-!= $check-mu-numberlike-arg:end/disp8
12993 $check-mu-numberlike-arg:check-addr:
12994     # if t is an addr and v is dereferenced, return
12995     {
12996       (is-mu-addr-type? %esi)  # => eax
12997       3d/compare-eax-and 0/imm32/false
12998       74/jump-if-= break/disp8
12999       8b/-> *(ebp+8) 0/r32/eax
13000       8b/-> *(eax+0x10) 0/r32/eax
13001       3d/compare-eax-and 0/imm32/false
13002       75/jump-if-!= $check-mu-numberlike-arg:end/disp8
13003     }
13004 $check-mu-numberlike-arg:output-checks:
13005     (check-mu-numberlike-output *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18))
13006 $check-mu-numberlike-arg:end:
13007     # . restore registers
13008     5e/pop-to-esi
13009     58/pop-to-eax
13010     # . epilogue
13011     89/<- %esp 5/r32/ebp
13012     5d/pop-to-ebp
13013     c3/return
13014 
13015 check-mu-numberlike-output:  # v: (addr stmt-var), stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13016     # . prologue
13017     55/push-ebp
13018     89/<- %ebp 4/r32/esp
13019     # . save registers
13020     50/push-eax
13021     56/push-esi
13022     # var t/esi: (addr type-tree) = lookup(v->value->type)
13023     8b/-> *(ebp+8) 0/r32/eax
13024     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13025     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
13026     89/<- %esi 0/r32/eax
13027 $check-mu-numberlike-output:check-int:
13028     # if t is an int, return
13029     (is-simple-mu-type? %esi 1)  # int => eax
13030     3d/compare-eax-and 0/imm32/false
13031     75/jump-if-!= $check-mu-numberlike-output:end/disp8
13032 $check-mu-numberlike-output:check-boolean:
13033     # if t is a boolean, return
13034     (is-simple-mu-type? %esi 5)  # boolean => eax
13035     3d/compare-eax-and 0/imm32/false
13036     75/jump-if-!= $check-mu-numberlike-output:end/disp8
13037 $check-mu-numberlike-output:check-byte:
13038     # if t is a byte, return
13039     (is-simple-mu-type? %esi 8)  # byte => eax
13040     3d/compare-eax-and 0/imm32/false
13041     75/jump-if-!= $check-mu-numberlike-output:end/disp8
13042     e9/jump $check-mu-numberlike-output:fail/disp32
13043 $check-mu-numberlike-output:end:
13044     # . restore registers
13045     5e/pop-to-esi
13046     58/pop-to-eax
13047     # . epilogue
13048     89/<- %esp 5/r32/ebp
13049     5d/pop-to-ebp
13050     c3/return
13051 
13052 $check-mu-numberlike-output:fail:
13053     # otherwise raise an error
13054     (write-buffered *(ebp+0x14) "fn ")
13055     8b/-> *(ebp+0x10) 0/r32/eax
13056     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13057     (write-buffered *(ebp+0x14) %eax)
13058     (write-buffered *(ebp+0x14) ": stmt ")
13059     8b/-> *(ebp+0xc) 0/r32/eax
13060     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
13061     (write-buffered *(ebp+0x14) %eax)
13062     (write-buffered *(ebp+0x14) ": only non-addr scalar args permitted\n")
13063     (flush *(ebp+0x14))
13064     (stop *(ebp+0x18) 1)
13065     # never gets here
13066 
13067 check-mu-copy-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13068     # . prologue
13069     55/push-ebp
13070     89/<- %ebp 4/r32/esp
13071     # . save registers
13072 $check-mu-copy-stmt:end:
13073     # . restore registers
13074     # . epilogue
13075     89/<- %esp 5/r32/ebp
13076     5d/pop-to-ebp
13077     c3/return
13078 
13079 check-mu-copy-to-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13080     # . prologue
13081     55/push-ebp
13082     89/<- %ebp 4/r32/esp
13083     # . save registers
13084 $check-mu-copy-to-stmt:end:
13085     # . restore registers
13086     # . epilogue
13087     89/<- %esp 5/r32/ebp
13088     5d/pop-to-ebp
13089     c3/return
13090 
13091 check-mu-compare-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13092     # . prologue
13093     55/push-ebp
13094     89/<- %ebp 4/r32/esp
13095     # . save registers
13096 $check-mu-compare-stmt:end:
13097     # . restore registers
13098     # . epilogue
13099     89/<- %esp 5/r32/ebp
13100     5d/pop-to-ebp
13101     c3/return
13102 
13103 check-mu-address-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13104     # . prologue
13105     55/push-ebp
13106     89/<- %ebp 4/r32/esp
13107     # . save registers
13108 $check-mu-address-stmt:end:
13109     # . restore registers
13110     # . epilogue
13111     89/<- %esp 5/r32/ebp
13112     5d/pop-to-ebp
13113     c3/return
13114 
13115 check-mu-get-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13116     # . prologue
13117     55/push-ebp
13118     89/<- %ebp 4/r32/esp
13119     # . save registers
13120     50/push-eax
13121     51/push-ecx
13122     52/push-edx
13123     53/push-ebx
13124     56/push-esi
13125     57/push-edi
13126     # esi = stmt
13127     8b/-> *(ebp+8) 6/r32/esi
13128     # - check for 0 inouts
13129     # var base/ecx: (addr var) = stmt->inouts->value
13130     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13131     3d/compare-eax-and 0/imm32/false
13132     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-inouts/disp32
13133     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13134     89/<- %ecx 0/r32/eax
13135 $check-mu-get-stmt:check-base:
13136     # - check base type
13137     # if it's an 'addr', check that it's in a register
13138     # var base-type/ebx: (addr type-tree) = lookup(base->type)
13139     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
13140     89/<- %ebx 0/r32/eax
13141     {
13142       81 7/subop/compare *ebx 0/imm32/false  # Type-tree-is-atom
13143       0f 85/jump-if-!= break/disp32
13144 $check-mu-get-stmt:base-is-compound:
13145       # if (type->left != addr) break
13146       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
13147       (is-simple-mu-type? %eax 2)  # addr => eax
13148       3d/compare-eax-and 0/imm32/false
13149       74/jump-if-= break/disp8
13150 $check-mu-get-stmt:base-is-addr:
13151       # now check for register
13152       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
13153       0f 84/jump-if-= $check-mu-get-stmt:error-base-type-addr-but-not-register/disp32
13154 $check-mu-get-stmt:base-is-addr-in-register:
13155       # type->left is now an addr; skip it
13156       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
13157       81 7/subop/compare *(eax+0xc) 0/imm32  # Type-tree-right
13158       0f 85/jump-if-!= $check-mu-get-stmt:error-bad-base/disp32
13159 $check-mu-get-stmt:base-is-addr-to-atom-in-register:
13160       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
13161       89/<- %ebx 0/r32/eax
13162     }
13163 $check-mu-get-stmt:check-base-typeinfo:
13164     # ensure type is a container
13165     # var base-type-id/ebx: type-id = base-type->value
13166     8b/-> *(ebx+4) 3/r32/ebx  # Type-tree-value
13167     (is-container? %ebx)  # => eax
13168     3d/compare-eax-and 0/imm32/false
13169     0f 84/jump-if-= $check-mu-get-stmt:error-bad-base/disp32
13170     # var base-typeinfo/edx: (addr typeinfo) = find-typeinfo(base-type-id)
13171     # . var container/ecx: (handle typeinfo)
13172     68/push 0/imm32
13173     68/push 0/imm32
13174     89/<- %ecx 4/r32/esp
13175     # .
13176     (find-typeinfo %ebx %ecx)
13177     (lookup *ecx *(ecx+4))  # => eax
13178     # . reclaim container
13179     81 0/subop/add %esp 8/imm32
13180     # .
13181     89/<- %edx 0/r32/eax
13182     # var offset/ecx: (addr stmt-var) = stmt->inouts->next
13183     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13184     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13185     89/<- %ecx 0/r32/eax
13186     # - check for 1 inout
13187     3d/compare-eax-and 0/imm32/false
13188     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-inouts/disp32
13189     # var offset/ecx: (addr var) = lookup(offset->value)
13190     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
13191     89/<- %ecx 0/r32/eax
13192     # - check for valid field
13193     81 7/subop/compare *(ecx+0x14) -1/imm32/uninitialized  # Var-offset
13194     0f 84/jump-if-= $check-mu-get-stmt:error-bad-field/disp32
13195     # - check for too many inouts
13196     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13197     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13198     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13199     3d/compare-eax-and 0/imm32/false
13200     0f 85/jump-if-!= $check-mu-get-stmt:error-too-many-inouts/disp32
13201     # var output/edi: (addr var) = stmt->outputs->value
13202     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13203     # - check for 0 outputs
13204     3d/compare-eax-and 0/imm32/false
13205     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-outputs/disp32
13206     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13207     89/<- %edi 0/r32/eax
13208 $check-mu-get-stmt:check-output-type:
13209     # - check output type
13210     # must be in register
13211     (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
13212     3d/compare-eax-and 0/imm32
13213     0f 84/jump-if-= $check-mu-get-stmt:error-output-not-in-register/disp32
13214     # must have a non-atomic type
13215     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
13216     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
13217     0f 85/jump-if-!= $check-mu-get-stmt:error-output-type-not-address/disp32
13218     # type must start with (addr ...)
13219     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
13220     (is-simple-mu-type? %eax 2)  # => eax
13221     3d/compare-eax-and 0/imm32/false
13222     0f 84/jump-if-= $check-mu-get-stmt:error-output-type-not-address/disp32
13223 $check-mu-get-stmt:check-output-type-match:
13224     # payload of addr type must match 'type' definition
13225     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
13226     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
13227     # if (payload->right == null) payload = payload->left
13228     81 7/subop/compare *(eax+0xc) 0/imm32/null  # Type-tree-right
13229     {
13230       75/jump-if-!= break/disp8
13231       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
13232     }
13233     89/<- %edi 0/r32/eax
13234     # . var output-name/ecx: (addr array byte)
13235     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13236     89/<- %ecx 0/r32/eax
13237     # . var base-typeinfo-entry/eax: (addr handle typeinfo-entry)
13238     (lookup *(edx+4) *(edx+8))  # Typeinfo-fields Typeinfo-fields => eax
13239     (get %eax %ecx 0x10)  # => eax
13240     # .
13241     (lookup *eax *(eax+4))  # => eax
13242     (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
13243     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
13244     # .
13245     (type-equal? %edi %eax)  # => eax
13246     3d/compare-eax-and 0/imm32/false
13247     0f 84/jump-if-= $check-mu-get-stmt:error-bad-output-type/disp32
13248     # - check for too many outputs
13249     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13250     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13251     3d/compare-eax-and 0/imm32/false
13252     0f 85/jump-if-!= $check-mu-get-stmt:error-too-many-outputs/disp32
13253 $check-mu-get-stmt:end:
13254     # . restore registers
13255     5f/pop-to-edi
13256     5e/pop-to-esi
13257     5b/pop-to-ebx
13258     5a/pop-to-edx
13259     59/pop-to-ecx
13260     58/pop-to-eax
13261     # . epilogue
13262     89/<- %esp 5/r32/ebp
13263     5d/pop-to-ebp
13264     c3/return
13265 
13266 $check-mu-get-stmt:error-too-few-inouts:
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 few inouts (2 required)\n")
13272     (flush *(ebp+0x10))
13273     (stop *(ebp+0x14) 1)
13274     # never gets here
13275 
13276 $check-mu-get-stmt:error-too-many-inouts:
13277     (write-buffered *(ebp+0x10) "fn ")
13278     8b/-> *(ebp+0xc) 0/r32/eax
13279     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13280     (write-buffered *(ebp+0x10) %eax)
13281     (write-buffered *(ebp+0x10) ": stmt get: too many inouts (2 required)\n")
13282     (flush *(ebp+0x10))
13283     (stop *(ebp+0x14) 1)
13284     # never gets here
13285 
13286 $check-mu-get-stmt:error-too-few-outputs:
13287     (write-buffered *(ebp+0x10) "fn ")
13288     8b/-> *(ebp+0xc) 0/r32/eax
13289     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13290     (write-buffered *(ebp+0x10) %eax)
13291     (write-buffered *(ebp+0x10) ": stmt get: must have an output\n")
13292     (flush *(ebp+0x10))
13293     (stop *(ebp+0x14) 1)
13294     # never gets here
13295 
13296 $check-mu-get-stmt:error-too-many-outputs:
13297     (write-buffered *(ebp+0x10) "fn ")
13298     8b/-> *(ebp+0xc) 0/r32/eax
13299     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13300     (write-buffered *(ebp+0x10) %eax)
13301     (write-buffered *(ebp+0x10) ": stmt get: too many outputs (1 required)\n")
13302     (flush *(ebp+0x10))
13303     (stop *(ebp+0x14) 1)
13304     # never gets here
13305 
13306 $check-mu-get-stmt:error-bad-base:
13307     # error("fn " fn ": stmt get: var '" base->name "' must have a 'type' definition\n")
13308     (write-buffered *(ebp+0x10) "fn ")
13309     8b/-> *(ebp+0xc) 0/r32/eax
13310     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13311     (write-buffered *(ebp+0x10) %eax)
13312     (write-buffered *(ebp+0x10) ": stmt get: var '")
13313     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13314     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13315     (lookup *eax *(eax+4))  # Var-name Var-name => eax
13316     (write-buffered *(ebp+0x10) %eax)
13317     (write-buffered *(ebp+0x10) "' must have a 'type' definition\n")
13318     (flush *(ebp+0x10))
13319     (stop *(ebp+0x14) 1)
13320     # never gets here
13321 
13322 $check-mu-get-stmt:error-base-type-addr-but-not-register:
13323     (write-buffered *(ebp+0x10) "fn ")
13324     8b/-> *(ebp+0xc) 0/r32/eax
13325     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13326     (write-buffered *(ebp+0x10) %eax)
13327     (write-buffered *(ebp+0x10) ": stmt get: var '")
13328     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13329     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13330     (lookup *eax *(eax+4))  # Var-name Var-name => eax
13331     (write-buffered *(ebp+0x10) %eax)
13332     (write-buffered *(ebp+0x10) "' is an 'addr' type, and so must live in a register\n")
13333     (flush *(ebp+0x10))
13334     (stop *(ebp+0x14) 1)
13335     # never gets here
13336 
13337 $check-mu-get-stmt:error-bad-field:
13338     # error("fn " fn ": stmt get: type " type " has no member called '" curr->name "'\n")
13339     (write-buffered *(ebp+0x10) "fn ")
13340     8b/-> *(ebp+0xc) 0/r32/eax
13341     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13342     (write-buffered *(ebp+0x10) %eax)
13343     (write-buffered *(ebp+0x10) ": stmt get: type '")
13344     # . write(Type-id->data[tmp])
13345     bf/copy-to-edi Type-id/imm32
13346     (write-buffered *(ebp+0x10) *(edi+ebx<<2+0xc))
13347     # .
13348     (write-buffered *(ebp+0x10) "' has no member called '")
13349     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13350     (write-buffered *(ebp+0x10) %eax)
13351     (write-buffered *(ebp+0x10) "'\n")
13352     (flush *(ebp+0x10))
13353     (stop *(ebp+0x14) 1)
13354     # never gets here
13355 
13356 $check-mu-get-stmt:error-output-not-in-register:
13357     (write-buffered *(ebp+0x10) "fn ")
13358     8b/-> *(ebp+0xc) 0/r32/eax
13359     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13360     (write-buffered *(ebp+0x10) %eax)
13361     (write-buffered *(ebp+0x10) ": stmt get: output '")
13362     (lookup *edi *(edi+4))  # Var-name Var-name => eax
13363     (write-buffered *(ebp+0x10) %eax)
13364     (write-buffered *(ebp+0x10) "' is not in a register\n")
13365     (flush *(ebp+0x10))
13366     (stop *(ebp+0x14) 1)
13367     # never gets here
13368 
13369 $check-mu-get-stmt:error-output-type-not-address:
13370     (write-buffered *(ebp+0x10) "fn ")
13371     8b/-> *(ebp+0xc) 0/r32/eax
13372     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13373     (write-buffered *(ebp+0x10) %eax)
13374     (write-buffered *(ebp+0x10) ": stmt get: output must be an address\n")
13375     (flush *(ebp+0x10))
13376     (stop *(ebp+0x14) 1)
13377     # never gets here
13378 
13379 $check-mu-get-stmt:error-bad-output-type:
13380     (write-buffered *(ebp+0x10) "fn ")
13381     8b/-> *(ebp+0xc) 0/r32/eax
13382     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13383     (write-buffered *(ebp+0x10) %eax)
13384     (write-buffered *(ebp+0x10) ": stmt get: wrong output type for member '")
13385     (write-buffered *(ebp+0x10) %ecx)
13386     (write-buffered *(ebp+0x10) "' of type '")
13387     bf/copy-to-edi Type-id/imm32
13388     (write-buffered *(ebp+0x10) *(edi+ebx<<2+0xc))
13389     (write-buffered *(ebp+0x10) "'\n")
13390     (flush *(ebp+0x10))
13391     (stop *(ebp+0x14) 1)
13392     # never gets here
13393 
13394 check-mu-index-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13395     # . prologue
13396     55/push-ebp
13397     89/<- %ebp 4/r32/esp
13398     # . save registers
13399     50/push-eax
13400     51/push-ecx
13401     52/push-edx
13402     53/push-ebx
13403     56/push-esi
13404     57/push-edi
13405     # esi = stmt
13406     8b/-> *(ebp+8) 6/r32/esi
13407     # - check for 0 inouts
13408     # var base/ecx: (addr var) = stmt->inouts->value
13409     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13410 $check-mu-index-stmt:check-no-inouts:
13411     3d/compare-eax-and 0/imm32
13412     0f 84/jump-if-= $check-mu-index-stmt:error-too-few-inouts/disp32
13413     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13414     89/<- %ecx 0/r32/eax
13415     # - check base type is either (addr array ...) in register or (array ...) on stack
13416     # var base-type/ebx: (addr type-tree) = lookup(base->type)
13417     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
13418     89/<- %ebx 0/r32/eax
13419     # if base-type is an atom, abort with a precise error
13420     81 7/subop/compare *ebx 0/imm32/false  # Type-tree-is-atom
13421     {
13422       74/jump-if-= break/disp8
13423       (is-simple-mu-type? %ebx 3)  # array => eax
13424       3d/compare-eax-and 0/imm32/false
13425       0f 85/jump-if-!= $check-mu-index-stmt:error-base-array-atom-type/disp32
13426       0f 84/jump-if-= $check-mu-index-stmt:error-base-non-array-type/disp32
13427     }
13428 $check-mu-index-stmt:base-is-compound:
13429     # if type->left not addr or array, abort
13430     {
13431       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
13432       (is-simple-mu-type? %eax 2)  # addr => eax
13433       3d/compare-eax-and 0/imm32/false
13434       75/jump-if-!= break/disp8
13435       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
13436       (is-simple-mu-type? %eax 3)  # array => eax
13437       3d/compare-eax-and 0/imm32/false
13438       75/jump-if-!= break/disp8
13439       e9/jump $check-mu-index-stmt:error-base-non-array-type/disp32
13440     }
13441     # if (type->left == addr) ensure type->right->left == array and type->register exists
13442     {
13443       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
13444       (is-simple-mu-type? %eax 2)  # addr => eax
13445       3d/compare-eax-and 0/imm32/false
13446       74/jump-if-= break/disp8
13447 $check-mu-index-stmt:base-is-addr:
13448       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
13449       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
13450       (is-simple-mu-type? %eax 3)  # array => eax
13451       3d/compare-eax-and 0/imm32/false
13452       0f 84/jump-if-= $check-mu-index-stmt:error-base-non-array-type/disp32
13453 $check-mu-index-stmt:check-base-addr-is-register:
13454       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
13455       0f 84/jump-if-= $check-mu-index-stmt:error-base-address-array-type-on-stack/disp32
13456     }
13457     # if (type->left == array) ensure type->register doesn't exist
13458     {
13459       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
13460       (is-simple-mu-type? %eax 3)  # array => eax
13461       3d/compare-eax-and 0/imm32/false
13462       74/jump-if-= break/disp8
13463 $check-mu-index-stmt:base-is-array:
13464       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
13465       0f 85/jump-if-!= $check-mu-index-stmt:error-base-array-type-in-register/disp32
13466     }
13467     # if (base-type->left == addr) base-type = base-type->right
13468     {
13469       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
13470       (is-simple-mu-type? %eax 2)  # addr => eax
13471       3d/compare-eax-and 0/imm32/false
13472       74/jump-if-= break/disp8
13473       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
13474       89/<- %ebx 0/r32/eax
13475     }
13476     # - check for 1 inout
13477     # var index/ecx: (addr stmt-var) = stmt->inouts->next->value
13478     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13479     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13480 $check-mu-index-stmt:check-single-inout:
13481     3d/compare-eax-and 0/imm32
13482     0f 84/jump-if-= $check-mu-index-stmt:error-too-few-inouts/disp32
13483     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13484     89/<- %ecx 0/r32/eax
13485     # - check index is either a literal or register
13486     # var index-type/edx: (addr type-tree)
13487     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
13488     89/<- %edx 0/r32/eax
13489     # if index type is an atom, it must be a literal or int
13490     81 7/subop/compare *edx 0/imm32/false  # Type-tree-is-atom
13491     {
13492       74/jump-if-= break/disp8
13493 $check-mu-index-stmt:index-type-is-atom:
13494       (is-simple-mu-type? %edx 0)  # literal => eax
13495       3d/compare-eax-and 0/imm32/false
13496       75/jump-if-!= $check-mu-index-stmt:index-type-done/disp8
13497       (is-simple-mu-type? %edx 1)  # int => eax
13498       3d/compare-eax-and 0/imm32/false
13499       75/jump-if-!= $check-mu-index-stmt:index-type-done/disp8
13500       (is-simple-mu-type? %edx 7)  # offset => eax
13501       3d/compare-eax-and 0/imm32/false
13502       0f 85/jump-if-!= $check-mu-index-stmt:error-index-offset-atom-type/disp32
13503       e9/jump $check-mu-index-stmt:error-invalid-index-type/disp32
13504     }
13505     # if index type is a non-atom: it must be an offset
13506     {
13507       75/jump-if-!= break/disp8
13508 $check-mu-index-stmt:index-type-is-non-atom:
13509       (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
13510       (is-simple-mu-type? %eax 7)  # offset => eax
13511       3d/compare-eax-and 0/imm32/false
13512       0f 84/jump-if-= $check-mu-index-stmt:error-invalid-index-type/disp32
13513     }
13514 $check-mu-index-stmt:index-type-done:
13515     # check index is either a literal or in a register
13516     {
13517       (is-simple-mu-type? %edx 0)  # literal => eax
13518       3d/compare-eax-and 0/imm32/false
13519       75/jump-if-!= break/disp8
13520 $check-mu-index-stmt:check-index-in-register:
13521       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
13522       0f 84/jump-if-= $check-mu-index-stmt:error-index-on-stack/disp32
13523     }
13524     # - if index is an 'int', check that element type of base has size 1, 2, 4 or 8 bytes.
13525     {
13526       (is-simple-mu-type? %edx 1)  # int => eax
13527       3d/compare-eax-and 0/imm32/false
13528       74/jump-if-= break/disp8
13529 $check-mu-index-stmt:check-index-can-be-int:
13530       (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13531       (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13532       (array-element-size %eax)  # => eax
13533       3d/compare-eax-and 1/imm32
13534       74/jump-if-= break/disp8
13535       3d/compare-eax-and 2/imm32
13536       74/jump-if-= break/disp8
13537       3d/compare-eax-and 4/imm32
13538       74/jump-if-= break/disp8
13539       3d/compare-eax-and 8/imm32
13540       74/jump-if-= break/disp8
13541       e9/jump $check-mu-index-stmt:error-index-needs-offset/disp32
13542     }
13543     # - check for too many inouts
13544     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13545     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => 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-inouts/disp32
13549     # - check for 0 outputs
13550     # var output/edi: (addr var) = stmt->outputs->value
13551     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13552     3d/compare-eax-and 0/imm32/false
13553     0f 84/jump-if-= $check-mu-index-stmt:error-too-few-outputs/disp32
13554     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13555     89/<- %edi 0/r32/eax
13556     # - check output type
13557     # must have a non-atomic type
13558     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
13559     89/<- %edx 0/r32/eax
13560     81 7/subop/compare *edx 0/imm32/false  # Type-tree-is-atom
13561     0f 85/jump-if-!= $check-mu-index-stmt:error-output-type-not-address/disp32
13562     # type must start with (addr ...)
13563     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
13564     (is-simple-mu-type? %eax 2)  # addr => eax
13565     3d/compare-eax-and 0/imm32/false
13566     0f 84/jump-if-= $check-mu-index-stmt:error-output-type-not-address/disp32
13567     # if tail(base-type) != tail(output-type) abort
13568     (type-tail %ebx)  # => eax
13569     89/<- %ebx 0/r32/eax
13570     (type-tail %edx)  # => eax
13571     (type-equal? %ebx %eax)  # => eax
13572     3d/compare-eax-and 0/imm32/false
13573     0f 84/jump-if-= $check-mu-index-stmt:error-bad-output-type/disp32
13574     # - check for too many outputs
13575     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13576     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13577     3d/compare-eax-and 0/imm32/false
13578     0f 85/jump-if-!= $check-mu-index-stmt:error-too-many-outputs/disp32
13579 $check-mu-index-stmt:end:
13580     # . restore registers
13581     5f/pop-to-edi
13582     5e/pop-to-esi
13583     5b/pop-to-ebx
13584     5a/pop-to-edx
13585     59/pop-to-ecx
13586     58/pop-to-eax
13587     # . epilogue
13588     89/<- %esp 5/r32/ebp
13589     5d/pop-to-ebp
13590     c3/return
13591 
13592 $check-mu-index-stmt:error-base-non-array-type:
13593     (write-buffered *(ebp+0x10) "fn ")
13594     8b/-> *(ebp+0xc) 0/r32/eax
13595     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13596     (write-buffered *(ebp+0x10) %eax)
13597     (write-buffered *(ebp+0x10) ": stmt index: var '")
13598     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13599     (write-buffered *(ebp+0x10) %eax)
13600     (write-buffered *(ebp+0x10) "' is not an array\n")
13601     (flush *(ebp+0x10))
13602     (stop *(ebp+0x14) 1)
13603     # never gets here
13604 
13605 $check-mu-index-stmt:error-base-array-atom-type:
13606     (write-buffered *(ebp+0x10) "fn ")
13607     8b/-> *(ebp+0xc) 0/r32/eax
13608     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13609     (write-buffered *(ebp+0x10) %eax)
13610     (write-buffered *(ebp+0x10) ": stmt index: array '")
13611     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13612     (write-buffered *(ebp+0x10) %eax)
13613     (write-buffered *(ebp+0x10) "' must specify the type of its elements\n")
13614     (flush *(ebp+0x10))
13615     (stop *(ebp+0x14) 1)
13616     # never gets here
13617 
13618 $check-mu-index-stmt:error-base-address-array-type-on-stack:
13619     (write-buffered *(ebp+0x10) "fn ")
13620     8b/-> *(ebp+0xc) 0/r32/eax
13621     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13622     (write-buffered *(ebp+0x10) %eax)
13623     (write-buffered *(ebp+0x10) ": stmt index: var '")
13624     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13625     (write-buffered *(ebp+0x10) %eax)
13626     (write-buffered *(ebp+0x10) "' is an addr to an array, and so must live in a register\n")
13627     (flush *(ebp+0x10))
13628     (stop *(ebp+0x14) 1)
13629     # never gets here
13630 
13631 $check-mu-index-stmt:error-base-array-type-in-register:
13632     (write-buffered *(ebp+0x10) "fn ")
13633     8b/-> *(ebp+0xc) 0/r32/eax
13634     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13635     (write-buffered *(ebp+0x10) %eax)
13636     (write-buffered *(ebp+0x10) ": stmt index: var '")
13637     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13638     (write-buffered *(ebp+0x10) %eax)
13639     (write-buffered *(ebp+0x10) "' is an array, and so must live on the stack\n")
13640     (flush *(ebp+0x10))
13641     (stop *(ebp+0x14) 1)
13642     # never gets here
13643 
13644 $check-mu-index-stmt:error-too-few-inouts:
13645     (write-buffered *(ebp+0x10) "fn ")
13646     8b/-> *(ebp+0xc) 0/r32/eax
13647     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13648     (write-buffered *(ebp+0x10) %eax)
13649     (write-buffered *(ebp+0x10) ": stmt index: too few inouts (2 required)\n")
13650     (flush *(ebp+0x10))
13651     (stop *(ebp+0x14) 1)
13652     # never gets here
13653 
13654 $check-mu-index-stmt:error-invalid-index-type:
13655     (write-buffered *(ebp+0x10) "fn ")
13656     8b/-> *(ebp+0xc) 0/r32/eax
13657     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13658     (write-buffered *(ebp+0x10) %eax)
13659     (write-buffered *(ebp+0x10) ": stmt index: second argument '")
13660     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13661     (write-buffered *(ebp+0x10) %eax)
13662     (write-buffered *(ebp+0x10) "' must be an int or offset\n")
13663     (flush *(ebp+0x10))
13664     (stop *(ebp+0x14) 1)
13665     # never gets here
13666 
13667 $check-mu-index-stmt:error-index-offset-atom-type:
13668     (write-buffered *(ebp+0x10) "fn ")
13669     8b/-> *(ebp+0xc) 0/r32/eax
13670     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13671     (write-buffered *(ebp+0x10) %eax)
13672     (write-buffered *(ebp+0x10) ": stmt index: offset '")
13673     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13674     (write-buffered *(ebp+0x10) %eax)
13675     (write-buffered *(ebp+0x10) "' must specify the type of array elements\n")
13676     (flush *(ebp+0x10))
13677     (stop *(ebp+0x14) 1)
13678     # never gets here
13679 
13680 $check-mu-index-stmt:error-index-on-stack:
13681     (write-buffered *(ebp+0x10) "fn ")
13682     8b/-> *(ebp+0xc) 0/r32/eax
13683     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13684     (write-buffered *(ebp+0x10) %eax)
13685     (write-buffered *(ebp+0x10) ": stmt index: second argument '")
13686     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13687     (write-buffered *(ebp+0x10) %eax)
13688     (write-buffered *(ebp+0x10) "' must be in a register\n")
13689     (flush *(ebp+0x10))
13690     (stop *(ebp+0x14) 1)
13691     # never gets here
13692 
13693 $check-mu-index-stmt:error-index-needs-offset:
13694     (write-buffered *(ebp+0x10) "fn ")
13695     8b/-> *(ebp+0xc) 0/r32/eax
13696     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13697     (write-buffered *(ebp+0x10) %eax)
13698     (write-buffered *(ebp+0x10) ": stmt index: cannot take an int for array '")
13699     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13700     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13701     (lookup *eax *(eax+4))  # Var-name Var-name => eax
13702     (write-buffered *(ebp+0x10) %eax)
13703     (write-buffered *(ebp+0x10) "'; create an offset instead. See mu.md for details.\n")
13704     (flush *(ebp+0x10))
13705     (stop *(ebp+0x14) 1)
13706     # never gets here
13707 
13708 $check-mu-index-stmt:error-too-many-inouts:
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: too many inouts (2 required)\n")
13714     (flush *(ebp+0x10))
13715     (stop *(ebp+0x14) 1)
13716     # never gets here
13717 
13718 $check-mu-index-stmt:error-too-few-outputs:
13719     (write-buffered *(ebp+0x10) "fn ")
13720     8b/-> *(ebp+0xc) 0/r32/eax
13721     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13722     (write-buffered *(ebp+0x10) %eax)
13723     (write-buffered *(ebp+0x10) ": stmt index: must have an output\n")
13724     (flush *(ebp+0x10))
13725     (stop *(ebp+0x14) 1)
13726     # never gets here
13727 
13728 $check-mu-index-stmt:error-too-many-outputs:
13729     (write-buffered *(ebp+0x10) "fn ")
13730     8b/-> *(ebp+0xc) 0/r32/eax
13731     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13732     (write-buffered *(ebp+0x10) %eax)
13733     (write-buffered *(ebp+0x10) ": stmt index: too many outputs (1 required)\n")
13734     (flush *(ebp+0x10))
13735     (stop *(ebp+0x14) 1)
13736     # never gets here
13737 
13738 $check-mu-index-stmt:error-output-not-in-register:
13739     (write-buffered *(ebp+0x10) "fn ")
13740     8b/-> *(ebp+0xc) 0/r32/eax
13741     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13742     (write-buffered *(ebp+0x10) %eax)
13743     (write-buffered *(ebp+0x10) ": stmt index: output '")
13744     (lookup *edi *(edi+4))  # Var-name Var-name => eax
13745     (write-buffered *(ebp+0x10) %eax)
13746     (write-buffered *(ebp+0x10) "' is not in a register\n")
13747     (flush *(ebp+0x10))
13748     (stop *(ebp+0x14) 1)
13749     # never gets here
13750 
13751 $check-mu-index-stmt:error-output-type-not-address:
13752     (write-buffered *(ebp+0x10) "fn ")
13753     8b/-> *(ebp+0xc) 0/r32/eax
13754     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13755     (write-buffered *(ebp+0x10) %eax)
13756     (write-buffered *(ebp+0x10) ": stmt index: output '")
13757     (lookup *edi *(edi+4))  # Var-name Var-name => eax
13758     (write-buffered *(ebp+0x10) %eax)
13759     (write-buffered *(ebp+0x10) "' must be an address\n")
13760     (flush *(ebp+0x10))
13761     (stop *(ebp+0x14) 1)
13762     # never gets here
13763 
13764 $check-mu-index-stmt:error-bad-output-type:
13765     (write-buffered *(ebp+0x10) "fn ")
13766     8b/-> *(ebp+0xc) 0/r32/eax
13767     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13768     (write-buffered *(ebp+0x10) %eax)
13769     (write-buffered *(ebp+0x10) ": stmt index: output '")
13770     (lookup *edi *(edi+4))  # Var-name Var-name => eax
13771     (write-buffered *(ebp+0x10) %eax)
13772     (write-buffered *(ebp+0x10) "' does not have the right type\n")
13773     (flush *(ebp+0x10))
13774     (stop *(ebp+0x14) 1)
13775     # never gets here
13776 
13777 check-mu-length-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13778     # . prologue
13779     55/push-ebp
13780     89/<- %ebp 4/r32/esp
13781     # . save registers
13782 $check-mu-length-stmt:end:
13783     # . restore registers
13784     # . epilogue
13785     89/<- %esp 5/r32/ebp
13786     5d/pop-to-ebp
13787     c3/return
13788 
13789 check-mu-compute-offset-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13790     # . prologue
13791     55/push-ebp
13792     89/<- %ebp 4/r32/esp
13793     # . save registers
13794 $check-mu-compute-offset-stmt:end:
13795     # . restore registers
13796     # . epilogue
13797     89/<- %esp 5/r32/ebp
13798     5d/pop-to-ebp
13799     c3/return
13800 
13801 check-mu-copy-object-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13802     # . prologue
13803     55/push-ebp
13804     89/<- %ebp 4/r32/esp
13805     # . save registers
13806 $check-mu-copy-object-stmt:end:
13807     # . restore registers
13808     # . epilogue
13809     89/<- %esp 5/r32/ebp
13810     5d/pop-to-ebp
13811     c3/return
13812 
13813 check-mu-allocate-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13814     # . prologue
13815     55/push-ebp
13816     89/<- %ebp 4/r32/esp
13817     # . save registers
13818 $check-mu-allocate-stmt:end:
13819     # . restore registers
13820     # . epilogue
13821     89/<- %esp 5/r32/ebp
13822     5d/pop-to-ebp
13823     c3/return
13824 
13825 check-mu-populate-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13826     # . prologue
13827     55/push-ebp
13828     89/<- %ebp 4/r32/esp
13829     # . save registers
13830 $check-mu-populate-stmt:end:
13831     # . restore registers
13832     # . epilogue
13833     89/<- %esp 5/r32/ebp
13834     5d/pop-to-ebp
13835     c3/return
13836 
13837 check-mu-populate-stream-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13838     # . prologue
13839     55/push-ebp
13840     89/<- %ebp 4/r32/esp
13841     # . save registers
13842 $check-mu-populate-stream-stmt:end:
13843     # . restore registers
13844     # . epilogue
13845     89/<- %esp 5/r32/ebp
13846     5d/pop-to-ebp
13847     c3/return
13848 
13849 check-mu-read-from-stream-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13850     # . prologue
13851     55/push-ebp
13852     89/<- %ebp 4/r32/esp
13853     # . save registers
13854 $check-mu-read-from-stream-stmt:end:
13855     # . restore registers
13856     # . epilogue
13857     89/<- %esp 5/r32/ebp
13858     5d/pop-to-ebp
13859     c3/return
13860 
13861 check-mu-write-to-stream-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13862     # . prologue
13863     55/push-ebp
13864     89/<- %ebp 4/r32/esp
13865     # . save registers
13866 $check-mu-write-to-stream-stmt:end:
13867     # . restore registers
13868     # . epilogue
13869     89/<- %esp 5/r32/ebp
13870     5d/pop-to-ebp
13871     c3/return
13872 
13873 check-mu-call:  # stmt: (addr stmt), callee: (addr function), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13874     # . prologue
13875     55/push-ebp
13876     89/<- %ebp 4/r32/esp
13877     # var type-parameters: (addr table (handle array byte) (addr type-tree) 8)
13878     68/push 0/imm32
13879     # var type-parameters-storage: (table (handle array byte) (addr type-tree) 8)
13880     81 5/subop/subtract %esp 0x60/imm32
13881     68/push 0x60/imm32/size
13882     68/push 0/imm32/read
13883     68/push 0/imm32/write
13884     # save a pointer to type-parameters-storage at type-parameters
13885     89/<- *(ebp-4) 4/r32/esp
13886     (clear-stream *(ebp-4))
13887     # . save registers
13888     50/push-eax
13889     51/push-ecx
13890     52/push-edx
13891     53/push-ebx
13892     56/push-esi
13893     57/push-edi
13894     # esi = stmt
13895     8b/-> *(ebp+8) 6/r32/esi
13896     # edi = callee
13897     8b/-> *(ebp+0xc) 7/r32/edi
13898     # var inouts/ecx: (addr stmt-var) = lookup(stmt->inouts)
13899     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13900     89/<- %ecx 0/r32/eax
13901     # var expected/edx: (addr list var) = lookup(f->inouts)
13902     (lookup *(edi+8) *(edi+0xc))  # Function-inouts Function-inouts => eax
13903     89/<- %edx 0/r32/eax
13904     {
13905 $check-mu-call:check-for-inouts:
13906       # if (inouts == 0) break
13907       81 7/subop/compare %ecx 0/imm32
13908       0f 84/jump-if-= break/disp32
13909       # if (expected == 0) error
13910       81 7/subop/compare %edx 0/imm32
13911       0f 84/jump-if-= break/disp32
13912 $check-mu-call:check-inout-type:
13913       # var v/eax: (addr v) = lookup(inouts->value)
13914       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
13915       # var t/ebx: (addr type-tree) = lookup(v->type)
13916       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
13917       89/<- %ebx 0/r32/eax
13918       # if (inouts->is-deref?) t = t->right  # TODO: check that t->left is an addr
13919       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
13920       {
13921         74/jump-if-= break/disp8
13922         (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
13923         89/<- %ebx 0/r32/eax
13924         # if t->right is null, t = t->left
13925         81 7/subop/compare *(ebx+0xc) 0/imm32  # Type-tree-right
13926         75/jump-if-!= break/disp8
13927         (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
13928         89/<- %ebx 0/r32/eax
13929       }
13930       # var v2/eax: (addr v) = lookup(expected->value)
13931       (lookup *edx *(edx+4))  # List-value List-value => eax
13932       # var t2/eax: (addr type-tree) = lookup(v2->type)
13933       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
13934       # if (t != t2) error
13935       (type-match? %eax %ebx *(ebp-4))  # => eax
13936       3d/compare-eax-and 0/imm32/false
13937       {
13938         0f 85/jump-if-!= break/disp32
13939         (write-buffered *(ebp+0x14) "fn ")
13940         8b/-> *(ebp+0x10) 0/r32/eax
13941         (lookup *eax *(eax+4))  # Function-name Function-name => eax
13942         (write-buffered *(ebp+0x14) %eax)
13943         (write-buffered *(ebp+0x14) ": call ")
13944         (lookup *edi *(edi+4))  # Function-name Function-name => eax
13945         (write-buffered *(ebp+0x14) %eax)
13946         (write-buffered *(ebp+0x14) ": type for inout '")
13947         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
13948         (lookup *eax *(eax+4))  # Var-name Var-name => eax
13949         (write-buffered *(ebp+0x14) %eax)
13950         (write-buffered *(ebp+0x14) "' is not right\n")
13951         (flush *(ebp+0x14))
13952         (stop *(ebp+0x18) 1)
13953       }
13954 $check-mu-call:continue-to-next-inout:
13955       # inouts = lookup(inouts->next)
13956       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
13957       89/<- %ecx 0/r32/eax
13958       # expected = lookup(expected->next)
13959       (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
13960       89/<- %edx 0/r32/eax
13961       #
13962       e9/jump loop/disp32
13963     }
13964 $check-mu-call:check-inout-count:
13965     # if (inouts == expected) proceed
13966     39/compare %ecx 2/r32/edx
13967     {
13968       0f 84/jump-if-= break/disp32
13969       # exactly one of the two is null
13970       # if (inouts == 0) error("too many inouts")
13971       {
13972         81 7/subop/compare %ecx 0/imm32
13973         0f 84/jump-if-= break/disp32
13974         (write-buffered *(ebp+0x14) "fn ")
13975         8b/-> *(ebp+0x10) 0/r32/eax
13976         (lookup *eax *(eax+4))  # Function-name Function-name => eax
13977         (write-buffered *(ebp+0x14) %eax)
13978         (write-buffered *(ebp+0x14) ": call ")
13979         (lookup *edi *(edi+4))  # Function-name Function-name => eax
13980         (write-buffered *(ebp+0x14) %eax)
13981         (write-buffered *(ebp+0x14) ": too many inouts\n")
13982         (flush *(ebp+0x14))
13983         (stop *(ebp+0x18) 1)
13984       }
13985       # if (expected == 0) error("too few inouts")
13986       {
13987         81 7/subop/compare %edx 0/imm32
13988         0f 84/jump-if-= break/disp32
13989         (write-buffered *(ebp+0x14) "fn ")
13990         8b/-> *(ebp+0x10) 0/r32/eax
13991         (lookup *eax *(eax+4))  # Function-name Function-name => eax
13992         (write-buffered *(ebp+0x14) %eax)
13993         (write-buffered *(ebp+0x14) ": call ")
13994         (lookup *edi *(edi+4))  # Function-name Function-name => eax
13995         (write-buffered *(ebp+0x14) %eax)
13996         (write-buffered *(ebp+0x14) ": too few inouts\n")
13997         (flush *(ebp+0x14))
13998         (stop *(ebp+0x18) 1)
13999       }
14000     }
14001 $check-mu-call:check-outputs:
14002     # var outputs/ecx: (addr stmt-var) = lookup(stmt->outputs)
14003     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
14004     89/<- %ecx 0/r32/eax
14005     # var expected/edx: (addr list var) = lookup(f->outputs)
14006     (lookup *(edi+0x10) *(edi+0x14))  # Function-outputs Function-outputs => eax
14007     89/<- %edx 0/r32/eax
14008     {
14009 $check-mu-call:check-for-outputs:
14010       # if (outputs == 0) break
14011       81 7/subop/compare %ecx 0/imm32
14012       0f 84/jump-if-= break/disp32
14013       # if (expected == 0) error
14014       81 7/subop/compare %edx 0/imm32
14015       0f 84/jump-if-= break/disp32
14016 $check-mu-call:check-output-type:
14017       # var v/eax: (addr v) = lookup(outputs->value)
14018       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
14019       # var t/ebx: (addr type-tree) = lookup(v->type)
14020       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
14021       89/<- %ebx 0/r32/eax
14022       # if (outputs->is-deref?) t = t->right  # TODO: check that t->left is an addr
14023       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
14024       {
14025         74/jump-if-= break/disp8
14026         (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
14027         89/<- %ebx 0/r32/eax
14028       }
14029       # var v2/eax: (addr v) = lookup(expected->value)
14030       (lookup *edx *(edx+4))  # List-value List-value => eax
14031       # var t2/eax: (addr type-tree) = lookup(v2->type)
14032       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
14033       # if (t != t2) error
14034       (type-match? %eax %ebx *(ebp-4))  # => eax
14035       3d/compare-eax-and 0/imm32/false
14036       {
14037         0f 85/jump-if-!= break/disp32
14038         (write-buffered *(ebp+0x14) "fn ")
14039         8b/-> *(ebp+0x10) 0/r32/eax
14040         (lookup *eax *(eax+4))  # Function-name Function-name => eax
14041         (write-buffered *(ebp+0x14) %eax)
14042         (write-buffered *(ebp+0x14) ": call ")
14043         (lookup *edi *(edi+4))  # Function-name Function-name => eax
14044         (write-buffered *(ebp+0x14) %eax)
14045         (write-buffered *(ebp+0x14) ": type for output '")
14046         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
14047         (lookup *eax *(eax+4))  # Var-name Var-name => eax
14048         (write-buffered *(ebp+0x14) %eax)
14049         (write-buffered *(ebp+0x14) "' is not right\n")
14050         (flush *(ebp+0x14))
14051         (stop *(ebp+0x18) 1)
14052       }
14053 $check-mu-call:check-output-register:
14054       # var v/eax: (addr v) = lookup(outputs->value)
14055       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
14056       # var r/ebx: (addr array byte) = lookup(v->register)
14057       (lookup *(eax+18) *(eax+0x1c))  # Var-register Var-register => eax
14058       89/<- %ebx 0/r32/eax
14059       # var v2/eax: (addr v) = lookup(expected->value)
14060       (lookup *edx *(edx+4))  # Stmt-var-value Stmt-var-value => eax
14061       # var r2/eax: (addr array byte) = lookup(v2->register)
14062       (lookup *(eax+18) *(eax+0x1c))  # Var-register Var-register => eax
14063       # if (r != r2) error
14064       (string-equal? %eax %ebx)  # => eax
14065       3d/compare-eax-and 0/imm32/false
14066       {
14067         0f 85/jump-if-!= break/disp32
14068         (write-buffered *(ebp+0x14) "fn ")
14069         8b/-> *(ebp+0x10) 0/r32/eax
14070         (lookup *eax *(eax+4))  # Function-name Function-name => eax
14071         (write-buffered *(ebp+0x14) %eax)
14072         (write-buffered *(ebp+0x14) ": call ")
14073         (lookup *edi *(edi+4))  # Function-name Function-name => eax
14074         (write-buffered *(ebp+0x14) %eax)
14075         (write-buffered *(ebp+0x14) ": register for output '")
14076         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
14077         (lookup *eax *(eax+4))  # Var-name Var-name => eax
14078         (write-buffered *(ebp+0x14) %eax)
14079         (write-buffered *(ebp+0x14) "' is not right\n")
14080         (flush *(ebp+0x14))
14081         (stop *(ebp+0x18) 1)
14082       }
14083 $check-mu-call:continue-to-next-output:
14084       # outputs = lookup(outputs->next)
14085       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
14086       89/<- %ecx 0/r32/eax
14087       # expected = lookup(expected->next)
14088       (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
14089       89/<- %edx 0/r32/eax
14090       #
14091       e9/jump loop/disp32
14092     }
14093 $check-mu-call:check-output-count:
14094     # if (outputs == expected) proceed
14095     39/compare %ecx 2/r32/edx
14096     {
14097       0f 84/jump-if-= break/disp32
14098       # exactly one of the two is null
14099       # if (outputs == 0) error("too many outputs")
14100       {
14101         81 7/subop/compare %ecx 0/imm32
14102         0f 84/jump-if-= break/disp32
14103         (write-buffered *(ebp+0x14) "fn ")
14104         8b/-> *(ebp+0x10) 0/r32/eax
14105         (lookup *eax *(eax+4))  # Function-name Function-name => eax
14106         (write-buffered *(ebp+0x14) %eax)
14107         (write-buffered *(ebp+0x14) ": call ")
14108         (lookup *edi *(edi+4))  # Function-name Function-name => eax
14109         (write-buffered *(ebp+0x14) %eax)
14110         (write-buffered *(ebp+0x14) ": too many outputs\n")
14111         (flush *(ebp+0x14))
14112         (stop *(ebp+0x18) 1)
14113       }
14114       # if (expected == 0) error("too few outputs")
14115       {
14116         81 7/subop/compare %edx 0/imm32
14117         0f 84/jump-if-= break/disp32
14118         (write-buffered *(ebp+0x14) "fn ")
14119         8b/-> *(ebp+0x10) 0/r32/eax
14120         (lookup *eax *(eax+4))  # Function-name Function-name => eax
14121         (write-buffered *(ebp+0x14) %eax)
14122         (write-buffered *(ebp+0x14) ": call ")
14123         (lookup *edi *(edi+4))  # Function-name Function-name => eax
14124         (write-buffered *(ebp+0x14) %eax)
14125         (write-buffered *(ebp+0x14) ": too few outputs\n")
14126         (flush *(ebp+0x14))
14127         (stop *(ebp+0x18) 1)
14128       }
14129     }
14130 $check-mu-call:end:
14131     # . restore registers
14132     5f/pop-to-edi
14133     5e/pop-to-esi
14134     5b/pop-to-ebx
14135     5a/pop-to-edx
14136     59/pop-to-ecx
14137     58/pop-to-eax
14138     # . reclaim locals exclusively on the stack
14139     81 0/subop/add %esp 0x70/imm32
14140     # . epilogue
14141     89/<- %esp 5/r32/ebp
14142     5d/pop-to-ebp
14143     c3/return
14144 
14145 # like type-equal? but takes literals into account
14146 type-match?:  # def: (addr type-tree), call: (addr type-tree), type-parameters: (addr table (handle array byte) (addr type-tree)) -> result/eax: boolean
14147     # . prologue
14148     55/push-ebp
14149     89/<- %ebp 4/r32/esp
14150     # if (call == literal) return true  # TODO: more precise
14151     (is-simple-mu-type? *(ebp+0xc) 0)  # literal => eax
14152     3d/compare-eax-and 0/imm32/false
14153     b8/copy-to-eax 1/imm32/true
14154     75/jump-if-!= $type-match?:end/disp8
14155 $type-match?:baseline:
14156     # otherwise fall back
14157     (type-component-match? *(ebp+8) *(ebp+0xc) *(ebp+0x10))  # => eax
14158 $type-match?:end:
14159     # . epilogue
14160     89/<- %esp 5/r32/ebp
14161     5d/pop-to-ebp
14162     c3/return
14163 
14164 type-component-match?:  # def: (addr type-tree), call: (addr type-tree), type-parameters: (addr table (handle array byte) (addr type-tree)) -> result/eax: boolean
14165     # . prologue
14166     55/push-ebp
14167     89/<- %ebp 4/r32/esp
14168     # . save registers
14169     51/push-ecx
14170     52/push-edx
14171     53/push-ebx
14172     # ecx = def
14173     8b/-> *(ebp+8) 1/r32/ecx
14174     # edx = call
14175     8b/-> *(ebp+0xc) 2/r32/edx
14176 $type-component-match?:compare-addr:
14177     # if (def == call) return true
14178     8b/-> %ecx 0/r32/eax  # Var-type
14179     39/compare %edx 0/r32/eax  # Var-type
14180     b8/copy-to-eax 1/imm32/true
14181     0f 84/jump-if-= $type-component-match?:end/disp32
14182     # if (def == 0) return false
14183     b8/copy-to-eax 0/imm32/false
14184     81 7/subop/compare %ecx 0/imm32  # Type-tree-is-atom
14185     0f 84/jump-if-= $type-component-match?:end/disp32
14186     # if (call == 0) return false
14187     81 7/subop/compare %edx 0/imm32  # Type-tree-is-atom
14188     0f 84/jump-if-= $type-component-match?:end/disp32
14189     # if def is a type parameter, just check in type-parameters
14190     {
14191 $type-component-match?:check-type-parameter:
14192       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
14193       74/jump-if-= break/disp8
14194       81 7/subop/compare *(ecx+4) 0xa/imm32/type-parameter  # Type-tree-value
14195       75/jump-if-!= break/disp8
14196 $type-component-match?:type-parameter:
14197       (type-parameter-match? *(ecx+8) *(ecx+0xc)  %edx  *(ebp+0x10))  # => eax
14198       e9/jump $type-component-match?:end/disp32
14199     }
14200     # if def is a list containing just a type parameter, just check in type-parameters
14201     {
14202 $type-component-match?:check-list-type-parameter:
14203       # if def is a list..
14204       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
14205       75/jump-if-!= break/disp8
14206       #   ..that's a singleton
14207       81 7/subop/compare *(ecx+0xc) 0/imm32  # Type-tree-left
14208       75/jump-if-!= break/disp8
14209       #   ..and whose head is a type parameter
14210       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14211       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14212       74/jump-if-= break/disp8
14213       81 7/subop/compare *(eax+4) 0xa/imm32/type-parameter  # Type-tree-value
14214       75/jump-if-!= break/disp8
14215 $type-component-match?:list-type-parameter:
14216       (type-parameter-match? *(eax+8) *(eax+0xc)  %edx  *(ebp+0x10))  # => eax
14217       e9/jump $type-component-match?:end/disp32
14218     }
14219 $type-component-match?:compare-atom-state:
14220     # if (def->is-atom? != call->is-atom?) return false
14221     8b/-> *ecx 3/r32/ebx  # Type-tree-is-atom
14222     39/compare *edx 3/r32/ebx  # Type-tree-is-atom
14223     b8/copy-to-eax 0/imm32/false
14224     0f 85/jump-if-!= $type-component-match?:end/disp32
14225     # if def->is-atom? return (def->value == call->value)
14226     {
14227 $type-component-match?:check-atom:
14228       81 7/subop/compare %ebx 0/imm32/false
14229       74/jump-if-= break/disp8
14230 $type-component-match?:is-atom:
14231       8b/-> *(ecx+4) 0/r32/eax  # Type-tree-value
14232       39/compare *(edx+4) 0/r32/eax  # Type-tree-value
14233       0f 94/set-if-= %al
14234       81 4/subop/and %eax 0xff/imm32
14235       e9/jump $type-component-match?:end/disp32
14236     }
14237 $type-component-match?:check-left:
14238     # if (!type-component-match?(def->left, call->left)) return false
14239     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14240     89/<- %ebx 0/r32/eax
14241     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
14242     (type-component-match? %ebx %eax *(ebp+0x10))  # => eax
14243     3d/compare-eax-and 0/imm32/false
14244     74/jump-if-= $type-component-match?:end/disp8
14245 $type-component-match?:check-right:
14246     # return type-component-match?(def->right, call->right)
14247     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
14248     89/<- %ebx 0/r32/eax
14249     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
14250     (type-component-match? %ebx %eax *(ebp+0x10))  # => eax
14251 $type-component-match?:end:
14252     # . restore registers
14253     5b/pop-to-ebx
14254     5a/pop-to-edx
14255     59/pop-to-ecx
14256     # . epilogue
14257     89/<- %esp 5/r32/ebp
14258     5d/pop-to-ebp
14259     c3/return
14260 
14261 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
14262     # . prologue
14263     55/push-ebp
14264     89/<- %ebp 4/r32/esp
14265     # . save registers
14266     51/push-ecx
14267     #
14268     (get-or-insert-handle *(ebp+0x14)  *(ebp+8) *(ebp+0xc)  0xc)  # => eax
14269     # if parameter wasn't saved, save it
14270     {
14271       81 7/subop/compare *eax 0/imm32
14272       75/jump-if-!= break/disp8
14273       8b/-> *(ebp+0x10) 1/r32/ecx
14274       89/<- *eax 1/r32/ecx
14275     }
14276     #
14277     (type-equal? *(ebp+0x10) *eax)  # => eax
14278 $type-parameter-match?:end:
14279     # . restore registers
14280     59/pop-to-ecx
14281     # . epilogue
14282     89/<- %esp 5/r32/ebp
14283     5d/pop-to-ebp
14284     c3/return
14285 
14286 size-of:  # v: (addr var) -> result/eax: int
14287     # . prologue
14288     55/push-ebp
14289     89/<- %ebp 4/r32/esp
14290     # . save registers
14291     51/push-ecx
14292     # var t/ecx: (addr type-tree) = lookup(v->type)
14293     8b/-> *(ebp+8) 1/r32/ecx
14294 #?     (write-buffered Stderr "size-of ")
14295 #?     (write-int32-hex-buffered Stderr %ecx)
14296 #?     (write-buffered Stderr Newline)
14297 #?     (write-buffered Stderr "type allocid: ")
14298 #?     (write-int32-hex-buffered Stderr *(ecx+8))
14299 #?     (write-buffered Stderr Newline)
14300 #?     (flush Stderr)
14301     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
14302     89/<- %ecx 0/r32/eax
14303     # if is-mu-array?(t) return size-of-array(t)
14304     {
14305       (is-mu-array? %ecx)  # => eax
14306       3d/compare-eax-and 0/imm32/false
14307       74/jump-if-= break/disp8
14308       (size-of-array %ecx)  # => eax
14309       eb/jump $size-of:end/disp8
14310     }
14311     # if is-mu-stream?(t) return size-of-stream(t)
14312     {
14313       (is-mu-stream? %ecx)  # => eax
14314       3d/compare-eax-and 0/imm32/false
14315       74/jump-if-= break/disp8
14316       (size-of-stream %ecx)  # => eax
14317       eb/jump $size-of:end/disp8
14318     }
14319     # if (!t->is-atom?) t = lookup(t->left)
14320     {
14321       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
14322       75/jump-if-!= break/disp8
14323       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14324       89/<- %ecx 0/r32/eax
14325     }
14326     # TODO: assert t->is-atom?
14327     (size-of-type-id *(ecx+4))  # Type-tree-value => eax
14328 $size-of:end:
14329     # . restore registers
14330     59/pop-to-ecx
14331     # . epilogue
14332     89/<- %esp 5/r32/ebp
14333     5d/pop-to-ebp
14334     c3/return
14335 
14336 size-of-deref:  # v: (addr var) -> result/eax: int
14337     # . prologue
14338     55/push-ebp
14339     89/<- %ebp 4/r32/esp
14340     # . save registers
14341     51/push-ecx
14342     # var t/ecx: (addr type-tree) = lookup(v->type)
14343     8b/-> *(ebp+8) 1/r32/ecx
14344     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
14345     89/<- %ecx 0/r32/eax
14346     # TODO: assert(t is an addr)
14347     # t = lookup(t->right)
14348     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
14349     89/<- %ecx 0/r32/eax
14350     # if is-mu-array?(t) return size-of-array(t)
14351     {
14352       (is-mu-array? %ecx)  # => eax
14353       3d/compare-eax-and 0/imm32/false
14354       74/jump-if-= break/disp8
14355       (size-of-array %ecx)  # => eax
14356       eb/jump $size-of-deref:end/disp8
14357     }
14358     # if is-mu-stream?(t) return size-of-stream(t)
14359     {
14360       (is-mu-stream? %ecx)  # => eax
14361       3d/compare-eax-and 0/imm32/false
14362       74/jump-if-= break/disp8
14363       (size-of-stream %ecx)  # => eax
14364       eb/jump $size-of-deref:end/disp8
14365     }
14366     # if (!t->is-atom?) t = lookup(t->left)
14367     {
14368       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
14369       75/jump-if-!= break/disp8
14370       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14371       89/<- %ecx 0/r32/eax
14372     }
14373     # TODO: assert t->is-atom?
14374     (size-of-type-id *(ecx+4))  # Type-tree-value => eax
14375 $size-of-deref:end:
14376     # . restore registers
14377     59/pop-to-ecx
14378     # . epilogue
14379     89/<- %esp 5/r32/ebp
14380     5d/pop-to-ebp
14381     c3/return
14382 
14383 is-mu-array?:  # t: (addr type-tree) -> result/eax: boolean
14384     # . prologue
14385     55/push-ebp
14386     89/<- %ebp 4/r32/esp
14387     # . save registers
14388     51/push-ecx
14389     # ecx = t
14390     8b/-> *(ebp+8) 1/r32/ecx
14391     # if t->is-atom?, return false
14392     81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
14393     75/jump-if-!= $is-mu-array?:return-false/disp8
14394     # if !t->left->is-atom?, return false
14395     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14396     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14397     74/jump-if-= $is-mu-array?:return-false/disp8
14398     # return t->left->value == array
14399     81 7/subop/compare *(eax+4) 3/imm32/array-type-id  # Type-tree-value
14400     0f 94/set-if-= %al
14401     81 4/subop/and %eax 0xff/imm32
14402     eb/jump $is-mu-array?:end/disp8
14403 $is-mu-array?:return-false:
14404     b8/copy-to-eax 0/imm32/false
14405 $is-mu-array?:end:
14406     # . restore registers
14407     59/pop-to-ecx
14408     # . epilogue
14409     89/<- %esp 5/r32/ebp
14410     5d/pop-to-ebp
14411     c3/return
14412 
14413 # size of a statically allocated array where the size is part of the type expression
14414 size-of-array:  # a: (addr type-tree) -> result/eax: int
14415     # . prologue
14416     55/push-ebp
14417     89/<- %ebp 4/r32/esp
14418     # . save registers
14419     51/push-ecx
14420     52/push-edx
14421     #
14422     8b/-> *(ebp+8) 1/r32/ecx
14423     # TODO: assert that a->left is 'array'
14424     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
14425     89/<- %ecx 0/r32/eax
14426     # var elem-type/edx: type-id = a->right->left->value
14427     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14428     8b/-> *(eax+4) 2/r32/edx  # Type-tree-value
14429     # TODO: assert that a->right->right->left->value == size
14430     # var array-size/ecx: int = a->right->right->left->value-size
14431     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
14432     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
14433     8b/-> *(eax+8) 1/r32/ecx  # Type-tree-value-size
14434     # return 4 + array-size * size-of(elem-type)
14435     (size-of-type-id-as-array-element %edx)  # => eax
14436     f7 4/subop/multiply-into-edx-eax %ecx
14437     05/add-to-eax 4/imm32  # for array size
14438     # TODO: check edx for overflow
14439 $size-of-array:end:
14440     # . restore registers
14441     5a/pop-to-edx
14442     59/pop-to-ecx
14443     # . epilogue
14444     89/<- %esp 5/r32/ebp
14445     5d/pop-to-ebp
14446     c3/return
14447 
14448 is-mu-stream?:  # t: (addr type-tree) -> result/eax: boolean
14449     # . prologue
14450     55/push-ebp
14451     89/<- %ebp 4/r32/esp
14452     # . save registers
14453     51/push-ecx
14454     # ecx = t
14455     8b/-> *(ebp+8) 1/r32/ecx
14456     # if t->is-atom?, return false
14457     81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
14458     75/jump-if-!= $is-mu-stream?:return-false/disp8
14459     # if !t->left->is-atom?, return false
14460     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14461     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14462     74/jump-if-= $is-mu-stream?:return-false/disp8
14463     # return t->left->value == stream
14464     81 7/subop/compare *(eax+4) 0xb/imm32/stream-type-id  # Type-tree-value
14465     0f 94/set-if-= %al
14466     81 4/subop/and %eax 0xff/imm32
14467     eb/jump $is-mu-stream?:end/disp8
14468 $is-mu-stream?:return-false:
14469     b8/copy-to-eax 0/imm32/false
14470 $is-mu-stream?:end:
14471     # . restore registers
14472     59/pop-to-ecx
14473     # . epilogue
14474     89/<- %esp 5/r32/ebp
14475     5d/pop-to-ebp
14476     c3/return
14477 
14478 # size of a statically allocated stream where the size is part of the type expression
14479 size-of-stream:  # a: (addr type-tree) -> result/eax: int
14480     # . prologue
14481     55/push-ebp
14482     89/<- %ebp 4/r32/esp
14483     #
14484     (size-of-array *(ebp+8))  # assumes we ignore the actual type name 'array' in the type
14485     05/add-to-eax 8/imm32  # for read/write pointers
14486 $size-of-stream:end:
14487     # . epilogue
14488     89/<- %esp 5/r32/ebp
14489     5d/pop-to-ebp
14490     c3/return
14491 
14492 size-of-type-id:  # t: type-id -> result/eax: int
14493     # . prologue
14494     55/push-ebp
14495     89/<- %ebp 4/r32/esp
14496     # . save registers
14497     51/push-ecx
14498     # var out/ecx: (handle typeinfo)
14499     68/push 0/imm32
14500     68/push 0/imm32
14501     89/<- %ecx 4/r32/esp
14502     # eax = t
14503     8b/-> *(ebp+8) 0/r32/eax
14504     # if t is a literal, return 0
14505     3d/compare-eax-and 0/imm32
14506     0f 84/jump-if-= $size-of-type-id:end/disp32  # eax changes type from type-id to int
14507     # if t is a byte, return 4 (because we don't really support non-multiples of 4)
14508     3d/compare-eax-and 8/imm32/byte
14509     {
14510       75/jump-if-!= break/disp8
14511       b8/copy-to-eax 4/imm32
14512       eb/jump $size-of-type-id:end/disp8
14513     }
14514     # if t is a handle, return 8
14515     3d/compare-eax-and 4/imm32/handle
14516     {
14517       75/jump-if-!= break/disp8
14518       b8/copy-to-eax 8/imm32
14519       eb/jump $size-of-type-id:end/disp8  # eax changes type from type-id to int
14520     }
14521     # if t is a user-defined type, return its size
14522     # TODO: support non-atom type
14523     (find-typeinfo %eax %ecx)
14524     {
14525       81 7/subop/compare *ecx 0/imm32
14526       74/jump-if-= break/disp8
14527 $size-of-type-id:user-defined:
14528       (lookup *ecx *(ecx+4))  # => eax
14529       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
14530       eb/jump $size-of-type-id:end/disp8
14531     }
14532     # otherwise return the word size
14533     b8/copy-to-eax 4/imm32
14534 $size-of-type-id:end:
14535     # . reclaim locals
14536     81 0/subop/add %esp 8/imm32
14537     # . restore registers
14538     59/pop-to-ecx
14539     # . epilogue
14540     89/<- %esp 5/r32/ebp
14541     5d/pop-to-ebp
14542     c3/return
14543 
14544 # Minor violation of our type system since it returns an addr. But we could
14545 # replace it with a handle some time.
14546 # Returns null if t is an atom.
14547 type-tail:  # t: (addr type-tree) -> out/eax: (addr type-tree)
14548     # . prologue
14549     55/push-ebp
14550     89/<- %ebp 4/r32/esp
14551     # . save registers
14552     51/push-ecx
14553     # eax = 0
14554     b8/copy-to-eax 0/imm32
14555     # ecx = t
14556     8b/-> *(ebp+8) 1/r32/ecx
14557 $type-tail:check-atom:
14558     # if t->is-atom? return 0
14559     81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
14560     0f 85/jump-if-!= $type-tail:end/disp32
14561     # var tail = t->right
14562     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
14563     89/<- %ecx 0/r32/eax
14564 $type-tail:check-singleton:
14565     # if (tail->right == 0) return tail->left
14566     {
14567       81 7/subop/compare *(ecx+0xc) 0/imm32  # Type-tree-right
14568       75/jump-if-!= break/disp8
14569       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14570       e9/jump $type-tail:end/disp32
14571     }
14572     # if tail->right->left is an array-capacity, return tail->left
14573     {
14574 $type-tail:check-array-capacity:
14575       (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
14576       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14577       75/jump-if-!= break/disp8
14578 $type-tail:check-array-capacity-1:
14579       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
14580       3d/compare-eax-and 0/imm32
14581       74/jump-if-= break/disp8
14582 $type-tail:check-array-capacity-2:
14583       (is-simple-mu-type? %eax 9)  # array-capacity => eax
14584       3d/compare-eax-and 0/imm32/false
14585       74/jump-if-= break/disp8
14586 $type-tail:array-capacity:
14587       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14588       eb/jump $type-tail:end/disp8
14589     }
14590 $type-tail:check-compound-left:
14591     # if !tail->left->is-atom? return tail->left
14592     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14593     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14594     74/jump-if-= $type-tail:end/disp8
14595 $type-tail:return-tail:
14596     # return tail
14597     89/<- %eax 1/r32/ecx
14598 $type-tail:end:
14599     # . restore registers
14600     59/pop-to-ecx
14601     # . epilogue
14602     89/<- %esp 5/r32/ebp
14603     5d/pop-to-ebp
14604     c3/return
14605 
14606 type-equal?:  # a: (addr type-tree), b: (addr type-tree) -> result/eax: boolean
14607     # . prologue
14608     55/push-ebp
14609     89/<- %ebp 4/r32/esp
14610     # . save registers
14611     51/push-ecx
14612     52/push-edx
14613     53/push-ebx
14614     # ecx = a
14615     8b/-> *(ebp+8) 1/r32/ecx
14616     # edx = b
14617     8b/-> *(ebp+0xc) 2/r32/edx
14618 $type-equal?:compare-addr:
14619     # if (a == b) return true
14620     8b/-> %ecx 0/r32/eax  # Var-type
14621     39/compare %edx 0/r32/eax  # Var-type
14622     b8/copy-to-eax 1/imm32/true
14623     0f 84/jump-if-= $type-equal?:end/disp32
14624 $type-equal?:compare-null-a:
14625     # if (a == 0) return false
14626     b8/copy-to-eax 0/imm32/false
14627     81 7/subop/compare %ecx 0/imm32
14628     0f 84/jump-if-= $type-equal?:end/disp32
14629 $type-equal?:compare-null-b:
14630     # if (b == 0) return false
14631     81 7/subop/compare %edx 0/imm32
14632     0f 84/jump-if-= $type-equal?:end/disp32
14633 $type-equal?:compare-atom-state:
14634     # if (a->is-atom? != b->is-atom?) return false
14635     8b/-> *ecx 3/r32/ebx  # Type-tree-is-atom
14636     39/compare *edx 3/r32/ebx  # Type-tree-is-atom
14637     b8/copy-to-eax 0/imm32/false
14638     0f 85/jump-if-!= $type-equal?:end/disp32
14639     # if a->is-atom? return (a->value == b->value)
14640     {
14641 $type-equal?:check-atom:
14642       81 7/subop/compare %ebx 0/imm32/false
14643       74/jump-if-= break/disp8
14644 $type-equal?:is-atom:
14645       8b/-> *(ecx+4) 0/r32/eax  # Type-tree-value
14646       39/compare *(edx+4) 0/r32/eax  # Type-tree-value
14647       0f 94/set-if-= %al
14648       81 4/subop/and %eax 0xff/imm32
14649       e9/jump $type-equal?:end/disp32
14650     }
14651 $type-equal?:check-left:
14652     # if (!type-equal?(a->left, b->left)) return false
14653     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14654     89/<- %ebx 0/r32/eax
14655     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
14656     (type-equal? %eax %ebx)  # => eax
14657     3d/compare-eax-and 0/imm32/false
14658     74/jump-if-= $type-equal?:end/disp8
14659 $type-equal?:check-right:
14660     # return type-equal?(a->right, b->right)
14661     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
14662     89/<- %ebx 0/r32/eax
14663     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
14664     (type-equal? %eax %ebx)  # => eax
14665 $type-equal?:end:
14666     # . restore registers
14667     5b/pop-to-ebx
14668     5a/pop-to-edx
14669     59/pop-to-ecx
14670     # . epilogue
14671     89/<- %esp 5/r32/ebp
14672     5d/pop-to-ebp
14673     c3/return
14674 
14675 #######################################################
14676 # Code-generation
14677 #######################################################
14678 
14679 == data
14680 
14681 # Global state added to each var record when performing code-generation.
14682 Curr-local-stack-offset:  # (addr int)
14683     0/imm32
14684 
14685 == code
14686 
14687 emit-subx:  # out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
14688     # . prologue
14689     55/push-ebp
14690     89/<- %ebp 4/r32/esp
14691     # . save registers
14692     50/push-eax
14693     # var curr/eax: (addr function) = *Program->functions
14694     (lookup *_Program-functions *_Program-functions->payload)  # => eax
14695     {
14696       # if (curr == null) break
14697       3d/compare-eax-and 0/imm32
14698       0f 84/jump-if-= break/disp32
14699       (emit-subx-function *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))
14700       # curr = lookup(curr->next)
14701       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
14702       e9/jump loop/disp32
14703     }
14704 $emit-subx:end:
14705     # . restore registers
14706     58/pop-to-eax
14707     # . epilogue
14708     89/<- %esp 5/r32/ebp
14709     5d/pop-to-ebp
14710     c3/return
14711 
14712 emit-subx-function:  # out: (addr buffered-file), f: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
14713     # . prologue
14714     55/push-ebp
14715     89/<- %ebp 4/r32/esp
14716     # some preprocessing
14717     (populate-mu-type-offsets-in-inouts *(ebp+0xc))
14718     # . save registers
14719     50/push-eax
14720     51/push-ecx
14721     52/push-edx
14722     # initialize some global state
14723     c7 0/subop/copy *Curr-block-depth 1/imm32  # Important: keep this in sync with the parse phase
14724     c7 0/subop/copy *Curr-local-stack-offset 0/imm32
14725     # ecx = f
14726     8b/-> *(ebp+0xc) 1/r32/ecx
14727     # var vars/edx: (stack (addr var) 256)
14728     81 5/subop/subtract %esp 0xc00/imm32
14729     68/push 0xc00/imm32/size
14730     68/push 0/imm32/top
14731     89/<- %edx 4/r32/esp
14732     # var name/eax: (addr array byte) = lookup(f->name)
14733     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
14734     #
14735     (write-buffered *(ebp+8) %eax)
14736     (write-buffered *(ebp+8) ":\n")
14737     (emit-subx-prologue *(ebp+8))
14738     # var body/eax: (addr block) = lookup(f->body)
14739     (lookup *(ecx+0x18) *(ecx+0x1c))  # Function-body Function-body => eax
14740     #
14741     (emit-subx-block *(ebp+8) %eax %edx *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
14742     (emit-subx-epilogue *(ebp+8))
14743     # TODO: validate that *Curr-block-depth and *Curr-local-stack-offset have
14744     # been cleaned up
14745 $emit-subx-function:end:
14746     # . reclaim locals
14747     81 0/subop/add %esp 0xc08/imm32
14748     # . restore registers
14749     5a/pop-to-edx
14750     59/pop-to-ecx
14751     58/pop-to-eax
14752     # . epilogue
14753     89/<- %esp 5/r32/ebp
14754     5d/pop-to-ebp
14755     c3/return
14756 
14757 populate-mu-type-offsets-in-inouts:  # f: (addr function)
14758     # . prologue
14759     55/push-ebp
14760     89/<- %ebp 4/r32/esp
14761     # . save registers
14762     50/push-eax
14763     51/push-ecx
14764     52/push-edx
14765     53/push-ebx
14766     57/push-edi
14767     # var next-offset/edx: int = 8
14768     ba/copy-to-edx 8/imm32
14769     # var curr/ecx: (addr list var) = lookup(f->inouts)
14770     8b/-> *(ebp+8) 1/r32/ecx
14771     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
14772     89/<- %ecx 0/r32/eax
14773     {
14774 $populate-mu-type-offsets-in-inouts:loop:
14775       81 7/subop/compare %ecx 0/imm32
14776       74/jump-if-= break/disp8
14777       # var v/ebx: (addr var) = lookup(curr->value)
14778       (lookup *ecx *(ecx+4))  # List-value List-value => eax
14779       89/<- %ebx 0/r32/eax
14780 #?       (lookup *ebx *(ebx+4))
14781 #?       (write-buffered Stderr "setting offset of fn inout ")
14782 #?       (write-buffered Stderr %eax)
14783 #?       (write-buffered Stderr "@")
14784 #?       (write-int32-hex-buffered Stderr %ebx)
14785 #?       (write-buffered Stderr " to ")
14786 #?       (write-int32-hex-buffered Stderr %edx)
14787 #?       (write-buffered Stderr Newline)
14788 #?       (flush Stderr)
14789       # v->offset = next-offset
14790       89/<- *(ebx+0x14) 2/r32/edx  # Var-offset
14791       # next-offset += size-of(v)
14792       (size-of %ebx)  # => eax
14793       01/add-to %edx 0/r32/eax
14794       # curr = lookup(curr->next)
14795       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
14796       89/<- %ecx 0/r32/eax
14797       #
14798       eb/jump loop/disp8
14799     }
14800 $populate-mu-type-offsets-in-inouts:end:
14801     # . restore registers
14802     5f/pop-to-edi
14803     5b/pop-to-ebx
14804     5a/pop-to-edx
14805     59/pop-to-ecx
14806     58/pop-to-eax
14807     # . epilogue
14808     89/<- %esp 5/r32/ebp
14809     5d/pop-to-ebp
14810     c3/return
14811 
14812 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)
14813     # . prologue
14814     55/push-ebp
14815     89/<- %ebp 4/r32/esp
14816     # . save registers
14817     50/push-eax
14818     51/push-ecx
14819     53/push-ebx
14820     56/push-esi
14821     # esi = stmts
14822     8b/-> *(ebp+0xc) 6/r32/esi
14823     #
14824     {
14825 $emit-subx-stmt-list:loop:
14826       81 7/subop/compare %esi 0/imm32
14827       0f 84/jump-if-= break/disp32
14828       # var curr-stmt/ecx: (addr stmt) = lookup(stmts->value)
14829       (lookup *esi *(esi+4))  # List-value List-value => eax
14830       89/<- %ecx 0/r32/eax
14831       {
14832 $emit-subx-stmt-list:check-for-block:
14833         81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
14834         75/jump-if-!= break/disp8
14835 $emit-subx-stmt-list:block:
14836         (emit-subx-block *(ebp+8) %ecx *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
14837       }
14838       {
14839 $emit-subx-stmt-list:check-for-stmt:
14840         81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
14841         0f 85/jump-if-!= break/disp32
14842 $emit-subx-stmt-list:stmt1:
14843         {
14844           (is-mu-branch? %ecx)  # => eax
14845           3d/compare-eax-and 0/imm32/false
14846           0f 84/jump-if-= break/disp32
14847 $emit-subx-stmt-list:branch-stmt:
14848 +-- 27 lines: # unconditional loops --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
14875 +-- 16 lines: # unconditional breaks -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
14891 +-- 38 lines: # simple conditional branches without a target -------------------------------------------------------------------------------------------------------------------------------------------------------
14929 +-- 19 lines: # conditional branches with an explicit target -------------------------------------------------------------------------------------------------------------------------------------------------------
14948         }
14949 $emit-subx-stmt-list:1-to-1:
14950         (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x18) *(ebp+0x1c))
14951         e9/jump $emit-subx-stmt-list:continue/disp32
14952       }
14953       {
14954 $emit-subx-stmt-list:check-for-var-def:
14955         81 7/subop/compare *ecx 2/imm32/var-def  # Stmt-tag
14956         75/jump-if-!= break/disp8
14957 $emit-subx-stmt-list:var-def:
14958         (emit-subx-var-def *(ebp+8) %ecx)
14959         (push *(ebp+0x10) *(ecx+4))  # Vardef-var
14960         (push *(ebp+0x10) *(ecx+8))  # Vardef-var
14961         (push *(ebp+0x10) 0)  # Live-var-register-spilled = 0 for vars on the stack
14962         #
14963         eb/jump $emit-subx-stmt-list:continue/disp8
14964       }
14965       {
14966 $emit-subx-stmt-list:check-for-reg-var-def:
14967         81 7/subop/compare *ecx 3/imm32/reg-var-def  # Stmt-tag
14968         0f 85/jump-if-!= break/disp32
14969 $emit-subx-stmt-list:reg-var-def:
14970         # TODO: ensure that there's exactly one output
14971         (push-output-and-maybe-emit-spill *(ebp+8) %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
14972         # emit the instruction as usual
14973         (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x18) *(ebp+0x1c))
14974         #
14975         eb/jump $emit-subx-stmt-list:continue/disp8
14976       }
14977 $emit-subx-stmt-list:continue:
14978       # TODO: raise an error on unrecognized Stmt-tag
14979       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
14980       89/<- %esi 0/r32/eax
14981       e9/jump loop/disp32
14982     }
14983 $emit-subx-stmt-list:emit-cleanup:
14984     (emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth)
14985 $emit-subx-stmt-list:clean-up:
14986     (clean-up-blocks *(ebp+0x10) *Curr-block-depth *(ebp+0x14))
14987 $emit-subx-stmt-list:end:
14988     # . restore registers
14989     5e/pop-to-esi
14990     5b/pop-to-ebx
14991     59/pop-to-ecx
14992     58/pop-to-eax
14993     # . epilogue
14994     89/<- %esp 5/r32/ebp
14995     5d/pop-to-ebp
14996     c3/return
14997 
14998 # 'later-stmts' includes 'stmt', but will behave the same even without it; reg-var-def stmts are guaranteed not to write to function outputs.
14999 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)
15000     # . prologue
15001     55/push-ebp
15002     89/<- %ebp 4/r32/esp
15003     # . save registers
15004     50/push-eax
15005     51/push-ecx
15006     52/push-edx
15007     # ecx = stmt
15008     8b/-> *(ebp+0xc) 1/r32/ecx
15009     # var sv/eax: (addr stmt-var) = lookup(curr-stmt->outputs)
15010     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
15011     # TODO: assert !sv->is-deref?
15012     # var v/ecx: (addr var) = lookup(sv->value)
15013     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15014     89/<- %ecx 0/r32/eax
15015     # v->block-depth = *Curr-block-depth
15016     8b/-> *Curr-block-depth 0/r32/eax
15017     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
15018 #?     (write-buffered Stderr "var ")
15019 #?     (lookup *ecx *(ecx+4))
15020 #?     (write-buffered Stderr %eax)
15021 #?     (write-buffered Stderr " at depth ")
15022 #?     (write-int32-hex-buffered Stderr *(ecx+0x10))
15023 #?     (write-buffered Stderr Newline)
15024 #?     (flush Stderr)
15025     # ensure that v is in a register
15026     81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
15027     0f 84/jump-if-= $push-output-and-maybe-emit-spill:abort/disp32
15028     # var emit-spill?/edx: boolean = not-yet-spilled-this-block? && will-not-write-some-register?(fn)
15029     (not-yet-spilled-this-block? %ecx *(ebp+0x10))  # => eax
15030     89/<- %edx 0/r32/eax
15031     3d/compare-eax-and 0/imm32/false
15032     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
15033     (will-not-write-some-register? %ecx *(ebp+0x14) *(ebp+0x18))  # => eax
15034     89/<- %edx 0/r32/eax
15035     # check emit-spill?
15036     3d/compare-eax-and 0/imm32/false
15037     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
15038     # TODO: assert(size-of(output) == 4)
15039     # *Curr-local-stack-offset -= 4
15040     81 5/subop/subtract *Curr-local-stack-offset 4/imm32
15041     # emit spill
15042     (emit-indent *(ebp+8) *Curr-block-depth)
15043     (write-buffered *(ebp+8) "ff 6/subop/push %")
15044     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
15045     (write-buffered *(ebp+8) %eax)
15046     (write-buffered *(ebp+8) Newline)
15047 $push-output-and-maybe-emit-spill:push:
15048     8b/-> *(ebp+0xc) 1/r32/ecx
15049     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
15050     # push(vars, {sv->value, emit-spill?})
15051     (push *(ebp+0x10) *eax)  # Stmt-var-value
15052     (push *(ebp+0x10) *(eax+4))  # Stmt-var-value
15053     (push *(ebp+0x10) %edx)
15054 $push-output-and-maybe-emit-spill:end:
15055     # . restore registers
15056     5a/pop-to-edx
15057     59/pop-to-ecx
15058     58/pop-to-eax
15059     # . epilogue
15060     89/<- %esp 5/r32/ebp
15061     5d/pop-to-ebp
15062     c3/return
15063 
15064 $push-output-and-maybe-emit-spill:abort:
15065     # error("var '" var->name "' initialized from an instruction must live in a register\n")
15066     (write-buffered *(ebp+0x1c) "var '")
15067     (write-buffered *(ebp+0x1c) *eax)  # Var-name
15068     (write-buffered *(ebp+0x1c) "' initialized from an instruction must live in a register\n")
15069     (flush *(ebp+0x1c))
15070     (stop *(ebp+0x20) 1)
15071     # never gets here
15072 
15073 emit-subx-cleanup-and-unconditional-nonlocal-branch:  # out: (addr buffered-file), stmt: (addr stmt1), vars: (addr stack live-var)
15074     # . prologue
15075     55/push-ebp
15076     89/<- %ebp 4/r32/esp
15077     # . save registers
15078     50/push-eax
15079     51/push-ecx
15080     # ecx = stmt
15081     8b/-> *(ebp+0xc) 1/r32/ecx
15082     # var target/eax: (addr array byte) = curr-stmt->inouts->value->name
15083     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15084     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15085     (lookup *eax *(eax+4))  # Var-name Var-name => eax
15086     # clean up until target block
15087     (emit-cleanup-code-until-target *(ebp+8) *(ebp+0x10) %eax)
15088     # emit jump to target block
15089     (emit-indent *(ebp+8) *Curr-block-depth)
15090     (write-buffered *(ebp+8) "e9/jump ")
15091     (write-buffered *(ebp+8) %eax)
15092     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
15093     (string-starts-with? %eax "break")
15094     3d/compare-eax-and 0/imm32/false
15095     {
15096       74/jump-if-= break/disp8
15097       (write-buffered *(ebp+8) ":break/disp32\n")
15098     }
15099     3d/compare-eax-and 0/imm32/false  # just in case the function call modified flags
15100     {
15101       75/jump-if-!= break/disp8
15102       (write-buffered *(ebp+8) ":loop/disp32\n")
15103     }
15104 $emit-subx-cleanup-and-unconditional-nonlocal-branch:end:
15105     # . restore registers
15106     59/pop-to-ecx
15107     58/pop-to-eax
15108     # . epilogue
15109     89/<- %esp 5/r32/ebp
15110     5d/pop-to-ebp
15111     c3/return
15112 
15113 is-mu-branch?:  # stmt: (addr stmt1) -> result/eax: boolean
15114     # . prologue
15115     55/push-ebp
15116     89/<- %ebp 4/r32/esp
15117     # . save registers
15118     51/push-ecx
15119     # ecx = lookup(stmt->operation)
15120     8b/-> *(ebp+8) 1/r32/ecx
15121     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
15122     89/<- %ecx 0/r32/eax
15123     # if (stmt->operation starts with "loop") return true
15124     (string-starts-with? %ecx "loop")  # => eax
15125     3d/compare-eax-and 0/imm32/false
15126     75/jump-if-not-equal $is-mu-branch?:end/disp8
15127     # otherwise return (stmt->operation starts with "break")
15128     (string-starts-with? %ecx "break")  # => eax
15129 $is-mu-branch?:end:
15130     # . restore registers
15131     59/pop-to-ecx
15132     # . epilogue
15133     89/<- %esp 5/r32/ebp
15134     5d/pop-to-ebp
15135     c3/return
15136 
15137 emit-reverse-break:  # out: (addr buffered-file), stmt: (addr stmt1)
15138     # . prologue
15139     55/push-ebp
15140     89/<- %ebp 4/r32/esp
15141     # . save registers
15142     50/push-eax
15143     # eax = stmt
15144     8b/-> *(ebp+0xc) 0/r32/eax
15145     #
15146     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
15147     (get Reverse-branch %eax 0x10 "reverse-branch: ")  # => eax: (addr handle array byte)
15148     (emit-indent *(ebp+8) *Curr-block-depth)
15149     (lookup *eax *(eax+4))  # => eax
15150     (write-buffered *(ebp+8) %eax)
15151     (write-buffered *(ebp+8) " break/disp32\n")
15152 $emit-reverse-break:end:
15153     # . restore registers
15154     58/pop-to-eax
15155     # . epilogue
15156     89/<- %esp 5/r32/ebp
15157     5d/pop-to-ebp
15158     c3/return
15159 
15160 == data
15161 
15162 # Table from Mu branch instructions to the reverse SubX opcodes for them.
15163 Reverse-branch:  # (table (handle array byte) (handle array byte))
15164   # a table is a stream
15165   0x140/imm32/write
15166   0/imm32/read
15167   0x140/imm32/size
15168   # data
15169   0x11/imm32/alloc-id   _string-break-if-=/imm32                0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
15170   0x11/imm32/alloc-id   _string-loop-if-=/imm32                 0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
15171   0x11/imm32/alloc-id   _string-break-if-!=/imm32               0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
15172   0x11/imm32/alloc-id   _string-loop-if-!=/imm32                0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
15173   0x11/imm32/alloc-id   _string-break-if-</imm32                0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
15174   0x11/imm32/alloc-id   _string-loop-if-</imm32                 0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
15175   0x11/imm32/alloc-id   _string-break-if->/imm32                0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
15176   0x11/imm32/alloc-id   _string-loop-if->/imm32                 0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
15177   0x11/imm32/alloc-id   _string-break-if-<=/imm32               0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
15178   0x11/imm32/alloc-id   _string-loop-if-<=/imm32                0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
15179   0x11/imm32/alloc-id   _string-break-if->=/imm32               0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
15180   0x11/imm32/alloc-id   _string-loop-if->=/imm32                0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
15181   0x11/imm32/alloc-id   _string-break-if-addr</imm32            0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
15182   0x11/imm32/alloc-id   _string-loop-if-addr</imm32             0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
15183   0x11/imm32/alloc-id   _string-break-if-addr>/imm32            0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
15184   0x11/imm32/alloc-id   _string-loop-if-addr>/imm32             0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
15185   0x11/imm32/alloc-id   _string-break-if-addr<=/imm32           0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
15186   0x11/imm32/alloc-id   _string-loop-if-addr<=/imm32            0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
15187   0x11/imm32/alloc-id   _string-break-if-addr>=/imm32           0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
15188   0x11/imm32/alloc-id   _string-loop-if-addr>=/imm32            0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
15189 
15190 == code
15191 
15192 emit-unconditional-jump-to-depth:  # out: (addr buffered-file), vars: (addr stack live-var), depth: int, label-suffix: (addr array byte)
15193     # . prologue
15194     55/push-ebp
15195     89/<- %ebp 4/r32/esp
15196     # . save registers
15197     50/push-eax
15198     51/push-ecx
15199     52/push-edx
15200     53/push-ebx
15201     56/push-esi
15202     # ecx = vars
15203     8b/-> *(ebp+0xc) 1/r32/ecx
15204     # var eax: int = vars->top
15205     8b/-> *ecx 0/r32/eax
15206     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
15207     8d/copy-address *(ecx+eax-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
15208     # var min/ecx: (addr handle var) = vars->data
15209     8d/copy-address *(ecx+8) 1/r32/ecx
15210     # edx = depth
15211     8b/-> *(ebp+0x10) 2/r32/edx
15212     {
15213 $emit-unconditional-jump-to-depth:loop:
15214       # if (curr < min) break
15215       39/compare %esi 1/r32/ecx
15216       0f 82/jump-if-addr< break/disp32
15217       # var v/ebx: (addr var) = lookup(*curr)
15218       (lookup *esi *(esi+4))  # => eax
15219       89/<- %ebx 0/r32/eax
15220       # if (v->block-depth < until-block-depth) break
15221       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
15222       0f 8c/jump-if-< break/disp32
15223       {
15224 $emit-unconditional-jump-to-depth:check:
15225         # if v->block-depth != until-block-depth, continue
15226         39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
15227         0f 85/jump-if-!= break/disp32
15228 $emit-unconditional-jump-to-depth:depth-found:
15229         # if v is not a literal, continue
15230         (size-of %ebx)  # => eax
15231         3d/compare-eax-and 0/imm32
15232         0f 85/jump-if-!= break/disp32
15233 $emit-unconditional-jump-to-depth:label-found:
15234         # emit unconditional jump, then return
15235         (emit-indent *(ebp+8) *Curr-block-depth)
15236         (write-buffered *(ebp+8) "e9/jump ")
15237         (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
15238         (write-buffered *(ebp+8) %eax)
15239         (write-buffered *(ebp+8) ":")
15240         (write-buffered *(ebp+8) *(ebp+0x14))
15241         (write-buffered *(ebp+8) "/disp32\n")
15242         eb/jump $emit-unconditional-jump-to-depth:end/disp8
15243       }
15244       # curr -= 12
15245       81 5/subop/subtract %esi 0xc/imm32
15246       e9/jump loop/disp32
15247     }
15248     # TODO: error if no label at 'depth' was found
15249 $emit-unconditional-jump-to-depth:end:
15250     # . restore registers
15251     5e/pop-to-esi
15252     5b/pop-to-ebx
15253     5a/pop-to-edx
15254     59/pop-to-ecx
15255     58/pop-to-eax
15256     # . epilogue
15257     89/<- %esp 5/r32/ebp
15258     5d/pop-to-ebp
15259     c3/return
15260 
15261 # emit clean-up code for 'vars' until some block depth
15262 # doesn't actually modify 'vars' so we need traverse manually inside the stack
15263 emit-cleanup-code-until-depth:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-depth: int
15264     # . prologue
15265     55/push-ebp
15266     89/<- %ebp 4/r32/esp
15267     # . save registers
15268     50/push-eax
15269     51/push-ecx
15270     52/push-edx
15271     53/push-ebx
15272     56/push-esi
15273 #?     (write-buffered Stderr "--- cleanup\n")
15274 #?     (flush Stderr)
15275     # ecx = vars
15276     8b/-> *(ebp+0xc) 1/r32/ecx
15277     # var esi: int = vars->top
15278     8b/-> *ecx 6/r32/esi
15279     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
15280     8d/copy-address *(ecx+esi-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
15281     # var min/ecx: (addr handle var) = vars->data
15282     81 0/subop/add %ecx 8/imm32
15283     # edx = until-block-depth
15284     8b/-> *(ebp+0x10) 2/r32/edx
15285     {
15286 $emit-cleanup-code-until-depth:loop:
15287       # if (curr < min) break
15288       39/compare %esi 1/r32/ecx
15289       0f 82/jump-if-addr< break/disp32
15290       # var v/ebx: (addr var) = lookup(*curr)
15291       (lookup *esi *(esi+4))  # => eax
15292       89/<- %ebx 0/r32/eax
15293 #?       (lookup *ebx *(ebx+4))  # Var-name
15294 #?       (write-buffered Stderr "var ")
15295 #?       (write-buffered Stderr %eax)
15296 #?       (write-buffered Stderr Newline)
15297 #?       (flush Stderr)
15298       # if (v->block-depth < until-block-depth) break
15299       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
15300       0f 8c/jump-if-< break/disp32
15301       # if v is in a register
15302       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
15303       {
15304         0f 84/jump-if-= break/disp32
15305         {
15306 $emit-cleanup-code-until-depth:check-for-previous-spill:
15307           8b/-> *(esi+8) 0/r32/eax  # Live-var-register-spilled
15308           3d/compare-eax-and 0/imm32/false
15309           74/jump-if-= break/disp8
15310 $emit-cleanup-code-until-depth:reclaim-var-in-register:
15311           (emit-indent *(ebp+8) *Curr-block-depth)
15312           (write-buffered *(ebp+8) "8f 0/subop/pop %")
15313           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
15314           (write-buffered *(ebp+8) %eax)
15315           (write-buffered *(ebp+8) Newline)
15316         }
15317         eb/jump $emit-cleanup-code-until-depth:continue/disp8
15318       }
15319       # otherwise v is on the stack
15320       {
15321         75/jump-if-!= break/disp8
15322 $emit-cleanup-code-until-depth:var-on-stack:
15323         (size-of %ebx)  # => eax
15324         # don't emit code for labels
15325         3d/compare-eax-and 0/imm32
15326         74/jump-if-= break/disp8
15327 $emit-cleanup-code-until-depth:reclaim-var-on-stack:
15328         (emit-indent *(ebp+8) *Curr-block-depth)
15329         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
15330         (write-int32-hex-buffered *(ebp+8) %eax)
15331         (write-buffered *(ebp+8) "/imm32\n")
15332       }
15333 $emit-cleanup-code-until-depth:continue:
15334       # curr -= 12
15335       81 5/subop/subtract %esi 0xc/imm32
15336       e9/jump loop/disp32
15337     }
15338 $emit-cleanup-code-until-depth:end:
15339     # . restore registers
15340     5e/pop-to-esi
15341     5b/pop-to-ebx
15342     5a/pop-to-edx
15343     59/pop-to-ecx
15344     58/pop-to-eax
15345     # . epilogue
15346     89/<- %esp 5/r32/ebp
15347     5d/pop-to-ebp
15348     c3/return
15349 
15350 # emit clean-up code for 'vars' until a given label is encountered
15351 # doesn't actually modify 'vars' so we need traverse manually inside the stack
15352 emit-cleanup-code-until-target:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-label: (addr array byte)
15353     # . prologue
15354     55/push-ebp
15355     89/<- %ebp 4/r32/esp
15356     # . save registers
15357     50/push-eax
15358     51/push-ecx
15359     52/push-edx
15360     53/push-ebx
15361     # ecx = vars
15362     8b/-> *(ebp+0xc) 1/r32/ecx
15363     # var eax: int = vars->top
15364     8b/-> *ecx 0/r32/eax
15365     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
15366     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
15367     # var min/ecx: (addr handle var) = vars->data
15368     81 0/subop/add %ecx 8/imm32
15369     {
15370 $emit-cleanup-code-until-target:loop:
15371       # if (curr < min) break
15372       39/compare %edx 1/r32/ecx
15373       0f 82/jump-if-addr< break/disp32
15374       # var v/ebx: (handle var) = lookup(*curr)
15375       (lookup *edx *(edx+4))  # => eax
15376       89/<- %ebx 0/r32/eax
15377       # if (v->name == until-block-label) break
15378       (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
15379       (string-equal? %eax *(ebp+0x10))  # => eax
15380       3d/compare-eax-and 0/imm32/false
15381       0f 85/jump-if-!= break/disp32
15382       # if v is in a register
15383       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
15384       {
15385         0f 84/jump-if-= break/disp32
15386         {
15387 $emit-cleanup-code-until-target:check-for-previous-spill:
15388           8b/-> *(edx+8) 0/r32/eax  # Live-var-register-spilled
15389           3d/compare-eax-and 0/imm32/false
15390           74/jump-if-= break/disp8
15391 $emit-cleanup-code-until-target:reclaim-var-in-register:
15392           (emit-indent *(ebp+8) *Curr-block-depth)
15393           (write-buffered *(ebp+8) "8f 0/subop/pop %")
15394           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
15395           (write-buffered *(ebp+8) %eax)
15396           (write-buffered *(ebp+8) Newline)
15397         }
15398         eb/jump $emit-cleanup-code-until-target:continue/disp8
15399       }
15400       # otherwise v is on the stack
15401       {
15402         75/jump-if-!= break/disp8
15403 $emit-cleanup-code-until-target:reclaim-var-on-stack:
15404         (size-of %ebx)  # => eax
15405         # don't emit code for labels
15406         3d/compare-eax-and 0/imm32
15407         74/jump-if-= break/disp8
15408         #
15409         (emit-indent *(ebp+8) *Curr-block-depth)
15410         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
15411         (write-int32-hex-buffered *(ebp+8) %eax)
15412         (write-buffered *(ebp+8) "/imm32\n")
15413       }
15414 $emit-cleanup-code-until-target:continue:
15415       # curr -= 12
15416       81 5/subop/subtract %edx 0xc/imm32
15417       e9/jump loop/disp32
15418     }
15419 $emit-cleanup-code-until-target:end:
15420     # . restore registers
15421     5b/pop-to-ebx
15422     5a/pop-to-edx
15423     59/pop-to-ecx
15424     58/pop-to-eax
15425     # . epilogue
15426     89/<- %esp 5/r32/ebp
15427     5d/pop-to-ebp
15428     c3/return
15429 
15430 # Return true if there isn't a variable in 'vars' with the same block-depth
15431 # and register as 'v'.
15432 # 'v' is guaranteed not to be within 'vars'.
15433 not-yet-spilled-this-block?:  # v: (addr var), vars: (addr stack live-var) -> result/eax: boolean
15434     # . prologue
15435     55/push-ebp
15436     89/<- %ebp 4/r32/esp
15437     # . save registers
15438     51/push-ecx
15439     52/push-edx
15440     53/push-ebx
15441     56/push-esi
15442     57/push-edi
15443     # ecx = vars
15444     8b/-> *(ebp+0xc) 1/r32/ecx
15445     # var eax: int = vars->top
15446     8b/-> *ecx 0/r32/eax
15447     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
15448     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
15449     # var min/ecx: (addr handle var) = vars->data
15450     8d/copy-address *(ecx+8) 1/r32/ecx
15451     # var depth/ebx: int = v->block-depth
15452     8b/-> *(ebp+8) 3/r32/ebx
15453     8b/-> *(ebx+0x10) 3/r32/ebx  # Var-block-depth
15454     # var needle/esi: (addr array byte) = v->register
15455     8b/-> *(ebp+8) 6/r32/esi
15456     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
15457     89/<- %esi 0/r32/eax
15458     {
15459 $not-yet-spilled-this-block?:loop:
15460       # if (curr < min) break
15461       39/compare %edx 1/r32/ecx
15462       0f 82/jump-if-addr< break/disp32
15463       # var cand/edi: (addr var) = lookup(*curr)
15464       (lookup *edx *(edx+4))  # => eax
15465       89/<- %edi 0/r32/eax
15466       # if (cand->block-depth < depth) break
15467       39/compare *(edi+0x10) 3/r32/ebx  # Var-block-depth
15468       0f 8c/jump-if-< break/disp32
15469       # var cand-reg/edi: (array array byte) = cand->reg
15470       (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
15471       89/<- %edi 0/r32/eax
15472       # if (cand-reg == null) continue
15473       {
15474 $not-yet-spilled-this-block?:check-reg:
15475         81 7/subop/compare %edi 0/imm32
15476         0f 84/jump-if-= break/disp32
15477         # if (cand-reg == needle) return true
15478         (string-equal? %esi %edi)  # => eax
15479         3d/compare-eax-and 0/imm32/false
15480         74/jump-if-= break/disp8
15481 $not-yet-spilled-this-block?:return-false:
15482         b8/copy-to-eax 0/imm32/false
15483         eb/jump $not-yet-spilled-this-block?:end/disp8
15484       }
15485 $not-yet-spilled-this-block?:continue:
15486       # curr -= 12
15487       81 5/subop/subtract %edx 0xc/imm32
15488       e9/jump loop/disp32
15489     }
15490 $not-yet-spilled-this-block?:return-true:
15491     # return true
15492     b8/copy-to-eax 1/imm32/true
15493 $not-yet-spilled-this-block?:end:
15494     # . restore registers
15495     5f/pop-to-edi
15496     5e/pop-to-esi
15497     5b/pop-to-ebx
15498     5a/pop-to-edx
15499     59/pop-to-ecx
15500     # . epilogue
15501     89/<- %esp 5/r32/ebp
15502     5d/pop-to-ebp
15503     c3/return
15504 
15505 # could the register of 'v' ever be written to by one of the vars in fn-outputs?
15506 will-not-write-some-register?:  # v: (addr var), stmts: (addr list stmt), fn: (addr function) -> result/eax: boolean
15507     # . prologue
15508     55/push-ebp
15509     89/<- %ebp 4/r32/esp
15510     # eax = v
15511     8b/-> *(ebp+8) 0/r32/eax
15512     # var reg/eax: (addr array byte) = lookup(v->register)
15513     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15514     # var target/eax: (addr var) = find-register(fn-outputs, reg)
15515     (find-register *(ebp+0x10) %eax)  # => eax
15516     # if (target == 0) return true
15517     {
15518       3d/compare-eax-and 0/imm32
15519       75/jump-if-!= break/disp8
15520       b8/copy-to-eax 1/imm32/true
15521       eb/jump $will-not-write-some-register?:end/disp8
15522     }
15523     # return !assigns-in-stmts?(stmts, target)
15524     (assigns-in-stmts? *(ebp+0xc) %eax)  # => eax
15525     3d/compare-eax-and 0/imm32/false
15526     # assume: true = 1, so no need to mask with 0x000000ff
15527     0f 94/set-if-= %al
15528 $will-not-write-some-register?:end:
15529     # . epilogue
15530     89/<- %esp 5/r32/ebp
15531     5d/pop-to-ebp
15532     c3/return
15533 
15534 # return fn output with matching register
15535 # always returns false if 'reg' is null
15536 find-register:  # fn: (addr function), reg: (addr array byte) -> result/eax: (addr var)
15537     # . prologue
15538     55/push-ebp
15539     89/<- %ebp 4/r32/esp
15540     # . save registers
15541     51/push-ecx
15542     # var curr/ecx: (addr list var) = lookup(fn->outputs)
15543     8b/-> *(ebp+8) 1/r32/ecx
15544     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
15545     89/<- %ecx 0/r32/eax
15546     {
15547 $find-register:loop:
15548       # if (curr == 0) break
15549       81 7/subop/compare %ecx 0/imm32
15550       74/jump-if-= break/disp8
15551       # eax = curr->value->register
15552       (lookup *ecx *(ecx+4))  # List-value List-value => eax
15553       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15554       # if (eax == reg) return curr->value
15555 $find-register:compare:
15556       (string-equal? *(ebp+0xc) %eax)  # => eax
15557       {
15558         3d/compare-eax-and 0/imm32/false
15559         74/jump-if-= break/disp8
15560 $find-register:found:
15561         (lookup *ecx *(ecx+4))  # List-value List-value => eax
15562         eb/jump $find-register:end/disp8
15563       }
15564       # curr = lookup(curr->next)
15565       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
15566       89/<- %ecx 0/r32/eax
15567       #
15568       eb/jump loop/disp8
15569     }
15570 $find-register:end:
15571     # . restore registers
15572     59/pop-to-ecx
15573     # . epilogue
15574     89/<- %esp 5/r32/ebp
15575     5d/pop-to-ebp
15576     c3/return
15577 
15578 assigns-in-stmts?:  # stmts: (addr list stmt), v: (addr var) -> result/eax: boolean
15579     # . prologue
15580     55/push-ebp
15581     89/<- %ebp 4/r32/esp
15582     # . save registers
15583     51/push-ecx
15584     # var curr/ecx: (addr list stmt) = stmts
15585     8b/-> *(ebp+8) 1/r32/ecx
15586     {
15587       # if (curr == 0) break
15588       81 7/subop/compare %ecx 0/imm32
15589       74/jump-if-= break/disp8
15590       # if assigns-in-stmt?(curr->value, v) return true
15591       (lookup *ecx *(ecx+4))  # List-value List-value => eax
15592       (assigns-in-stmt? %eax *(ebp+0xc))  # => eax
15593       3d/compare-eax-and 0/imm32/false
15594       75/jump-if-!= break/disp8
15595       # curr = lookup(curr->next)
15596       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
15597       89/<- %ecx 0/r32/eax
15598       #
15599       eb/jump loop/disp8
15600     }
15601 $assigns-in-stmts?:end:
15602     # . restore registers
15603     59/pop-to-ecx
15604     # . epilogue
15605     89/<- %esp 5/r32/ebp
15606     5d/pop-to-ebp
15607     c3/return
15608 
15609 assigns-in-stmt?:  # stmt: (addr stmt), v: (addr var) -> result/eax: boolean
15610     # . prologue
15611     55/push-ebp
15612     89/<- %ebp 4/r32/esp
15613     # . save registers
15614     51/push-ecx
15615     # ecx = stmt
15616     8b/-> *(ebp+8) 1/r32/ecx
15617     # if stmt is a stmt1, return assigns-in-stmt-vars?(stmt->outputs, v)
15618     {
15619       81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
15620       75/jump-if-!= break/disp8
15621       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
15622       (assigns-in-stmt-vars? %eax *(ebp+0xc))  # => eax
15623       eb/jump $assigns-in-stmt?:end/disp8
15624     }
15625     # if stmt is a block, return assigns-in-stmts?(stmt->stmts, v)
15626     {
15627       81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
15628       75/jump-if-!= break/disp8
15629       (lookup *(ecx+4) *(ecx+8))  # Block-stmts Block-stmts => eax
15630       (assigns-in-stmts? %eax *(ebp+0xc))  # => eax
15631       eb/jump $assigns-in-stmt?:end/disp8
15632     }
15633     # otherwise return false
15634     b8/copy 0/imm32/false
15635 $assigns-in-stmt?:end:
15636     # . restore registers
15637     59/pop-to-ecx
15638     # . epilogue
15639     89/<- %esp 5/r32/ebp
15640     5d/pop-to-ebp
15641     c3/return
15642 
15643 assigns-in-stmt-vars?:  # stmt-var: (addr stmt-var), v: (addr var) -> result/eax: boolean
15644     # . prologue
15645     55/push-ebp
15646     89/<- %ebp 4/r32/esp
15647     # . save registers
15648     51/push-ecx
15649     # var curr/ecx: (addr stmt-var) = stmt-var
15650     8b/-> *(ebp+8) 1/r32/ecx
15651     {
15652       # if (curr == 0) break
15653       81 7/subop/compare %ecx 0/imm32
15654       74/jump-if-= break/disp8
15655       # eax = lookup(curr->value)
15656       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
15657       # if (eax == v  &&  curr->is-deref? == false) return true
15658       {
15659         39/compare *(ebp+0xc) 0/r32/eax
15660         75/jump-if-!= break/disp8
15661         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
15662         75/jump-if-!= break/disp8
15663         b8/copy-to-eax 1/imm32/true
15664         eb/jump $assigns-in-stmt-vars?:end/disp8
15665       }
15666       # curr = lookup(curr->next)
15667       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
15668       89/<- %ecx 0/r32/eax
15669       #
15670       eb/jump loop/disp8
15671     }
15672 $assigns-in-stmt-vars?:end:
15673     # . restore registers
15674     59/pop-to-ecx
15675     # . epilogue
15676     89/<- %esp 5/r32/ebp
15677     5d/pop-to-ebp
15678     c3/return
15679 
15680 # is there a var before 'v' with the same block-depth and register on the 'vars' stack?
15681 # v is guaranteed to be within vars
15682 # 'start' is provided as an optimization, a pointer within vars
15683 # *start == v
15684 same-register-spilled-before?:  # v: (addr var), vars: (addr stack (handle var)), start: (addr var) -> result/eax: boolean
15685     # . prologue
15686     55/push-ebp
15687     89/<- %ebp 4/r32/esp
15688     # . save registers
15689     51/push-ecx
15690     52/push-edx
15691     53/push-ebx
15692     56/push-esi
15693     57/push-edi
15694     # ecx = v
15695     8b/-> *(ebp+8) 1/r32/ecx
15696     # var reg/edx: (addr array byte) = lookup(v->register)
15697     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
15698     89/<- %edx 0/r32/eax
15699     # var depth/ebx: int = v->block-depth
15700     8b/-> *(ecx+0x10) 3/r32/ebx  # Var-block-depth
15701     # var min/ecx: (addr handle var) = vars->data
15702     8b/-> *(ebp+0xc) 1/r32/ecx
15703     81 0/subop/add %ecx 8/imm32
15704     # TODO: check that start >= min and start < &vars->data[top]
15705     # TODO: check that *start == v
15706     # var curr/esi: (addr handle var) = start
15707     8b/-> *(ebp+0x10) 6/r32/esi
15708     # curr -= 8
15709     81 5/subop/subtract %esi 8/imm32
15710     {
15711 $same-register-spilled-before?:loop:
15712       # if (curr < min) break
15713       39/compare %esi 1/r32/ecx
15714       0f 82/jump-if-addr< break/disp32
15715       # var x/eax: (addr var) = lookup(*curr)
15716       (lookup *esi *(esi+4))  # => eax
15717       # if (x->block-depth < depth) break
15718       39/compare *(eax+0x10) 3/r32/ebx  # Var-block-depth
15719       0f 8c/jump-if-< break/disp32
15720       # if (x->register == 0) continue
15721       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
15722       74/jump-if-= $same-register-spilled-before?:continue/disp8
15723       # if (x->register == reg) return true
15724       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15725       (string-equal? %eax %edx)  # => eax
15726       3d/compare-eax-and 0/imm32/false
15727       b8/copy-to-eax 1/imm32/true
15728       75/jump-if-!= $same-register-spilled-before?:end/disp8
15729 $same-register-spilled-before?:continue:
15730       # curr -= 8
15731       81 5/subop/subtract %esi 8/imm32
15732       e9/jump loop/disp32
15733     }
15734 $same-register-spilled-before?:false:
15735     b8/copy-to-eax 0/imm32/false
15736 $same-register-spilled-before?:end:
15737     # . restore registers
15738     5f/pop-to-edi
15739     5e/pop-to-esi
15740     5b/pop-to-ebx
15741     5a/pop-to-edx
15742     59/pop-to-ecx
15743     # . epilogue
15744     89/<- %esp 5/r32/ebp
15745     5d/pop-to-ebp
15746     c3/return
15747 
15748 # Clean up global state for 'vars' until some block depth (inclusive).
15749 #
15750 # This would be a simple series of pops, if it wasn't for fn outputs, which
15751 # can occur anywhere in the stack.
15752 # So we have to _compact_ the entire array underlying the stack.
15753 #
15754 # We want to allow a fn output register to be written to by locals before the
15755 # output is set.
15756 # So fn outputs can't just be pushed at the start of the function.
15757 #
15758 # We want to allow other locals to shadow a fn output register after the
15759 # output is set.
15760 # So the output can't just always override anything in the stack. Sequence matters.
15761 clean-up-blocks:  # vars: (addr stack live-var), until-block-depth: int, fn: (addr function)
15762     # pseudocode:
15763     #   to = vars->top  (which points outside the stack)
15764     #   while true
15765     #     if to <= 0
15766     #       break
15767     #     var v = vars->data[to-1]
15768     #     if v.depth < until and !in-function-outputs?(fn, v)
15769     #       break
15770     #     --to
15771     #   from = to
15772     #   while true
15773     #     if from >= vars->top
15774     #       break
15775     #     assert(from >= to)
15776     #     v = vars->data[from]
15777     #     if in-function-outputs?(fn, v)
15778     #       if from > to
15779     #         vars->data[to] = vars->data[from]
15780     #       ++to
15781     #     ++from
15782     #   vars->top = to
15783     #
15784     # . prologue
15785     55/push-ebp
15786     89/<- %ebp 4/r32/esp
15787     # . save registers
15788     50/push-eax
15789     52/push-edx
15790     53/push-ebx
15791     56/push-esi
15792     57/push-edi
15793     # ebx = vars
15794     8b/-> *(ebp+8) 3/r32/ebx
15795     # edx = until-block-depth
15796     8b/-> *(ebp+0xc) 2/r32/edx
15797 $clean-up-blocks:phase1:
15798     # var to/edi: int = vars->top
15799     8b/-> *ebx 7/r32/edi
15800     {
15801 $clean-up-blocks:loop1:
15802       # if (to <= 0) break
15803       81 7/subop/compare %edi 0/imm32
15804       7e/jump-if-<= break/disp8
15805       # var v/eax: (addr var) = lookup(vars->data[to-1]->var)
15806       8d/copy-address *(ebx+edi-4) 0/r32/eax  # vars + 8 + to - 12
15807       (lookup *eax *(eax+4))  # => eax
15808       # if (v->block-depth >= until-block-depth) continue
15809       39/compare *(eax+0x10) 2/r32/edx  # Var-block-depth
15810       {
15811         7d/jump-if->= break/disp8
15812         # if (!in-function-outputs?(fn, v)) break
15813         (in-function-outputs? *(ebp+0x10) %eax)  # => eax
15814         3d/compare-eax-and 0/imm32/false
15815         74/jump-if-= $clean-up-blocks:phase2/disp8
15816       }
15817 $clean-up-blocks:loop1-continue:
15818       # --to
15819       81 5/subop/subtract %edi 0xc/imm32
15820       #
15821       eb/jump loop/disp8
15822     }
15823 $clean-up-blocks:phase2:
15824     # var from/esi: int = to
15825     89/<- %esi 7/r32/edi
15826     {
15827 $clean-up-blocks:loop2:
15828       # if (from >= vars->top) break
15829       3b/compare 6/r32/esi *ebx
15830       7d/jump-if->= break/disp8
15831       # var v/eax: (addr var) = lookup(vars->data[from]->var)
15832       8d/copy-address *(ebx+esi+8) 0/r32/eax
15833       (lookup *eax *(eax+4))  # => eax
15834       # if !in-function-outputs?(fn, v) continue
15835       (in-function-outputs? *(ebp+0x10) %eax)  # => eax
15836       3d/compare-eax-and 0/imm32/false
15837       74/jump-if-= $clean-up-blocks:loop2-continue/disp8
15838       # invariant: from >= to
15839       # if (from > to) vars->data[to] = vars->data[from]
15840       {
15841         39/compare %esi 7/r32/edi
15842         7e/jump-if-<= break/disp8
15843         56/push-esi
15844         57/push-edi
15845         # . var from/esi: (addr byte) = &vars->data[from]
15846         8d/copy-address *(ebx+esi+8) 6/r32/esi
15847         # . var to/edi: (addr byte) = &vars->data[to]
15848         8d/copy-address *(ebx+edi+8) 7/r32/edi
15849         # .
15850         8b/-> *esi 0/r32/eax
15851         89/<- *edi 0/r32/eax
15852         8b/-> *(esi+4) 0/r32/eax
15853         89/<- *(edi+4) 0/r32/eax
15854         8b/-> *(esi+8) 0/r32/eax
15855         89/<- *(edi+8) 0/r32/eax
15856         5f/pop-to-edi
15857         5e/pop-to-esi
15858       }
15859       # ++to
15860       81 0/subop/add %edi 0xc/imm32
15861 $clean-up-blocks:loop2-continue:
15862       # ++from
15863       81 0/subop/add %esi 0xc/imm32
15864       #
15865       eb/jump loop/disp8
15866     }
15867     89/<- *ebx 7/r32/edi
15868 $clean-up-blocks:end:
15869     # . restore registers
15870     5f/pop-to-edi
15871     5e/pop-to-esi
15872     5b/pop-to-ebx
15873     5a/pop-to-edx
15874     58/pop-to-eax
15875     # . epilogue
15876     89/<- %esp 5/r32/ebp
15877     5d/pop-to-ebp
15878     c3/return
15879 
15880 in-function-outputs?:  # fn: (addr function), target: (addr var) -> result/eax: boolean
15881     # . prologue
15882     55/push-ebp
15883     89/<- %ebp 4/r32/esp
15884     # . save registers
15885     51/push-ecx
15886     # var curr/ecx: (addr list var) = lookup(fn->outputs)
15887     8b/-> *(ebp+8) 1/r32/ecx
15888     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
15889     89/<- %ecx 0/r32/eax
15890     # while curr != null
15891     {
15892       81 7/subop/compare %ecx 0/imm32
15893       74/jump-if-= break/disp8
15894       # var v/eax: (addr var) = lookup(curr->value)
15895       (lookup *ecx *(ecx+4))  # List-value List-value => eax
15896       # if (v == target) return true
15897       39/compare *(ebp+0xc) 0/r32/eax
15898       b8/copy-to-eax 1/imm32/true
15899       74/jump-if-= $in-function-outputs?:end/disp8
15900       # curr = curr->next
15901       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
15902       89/<- %ecx 0/r32/eax
15903       #
15904       eb/jump loop/disp8
15905     }
15906     b8/copy-to-eax 0/imm32
15907 $in-function-outputs?:end:
15908     # . restore registers
15909     59/pop-to-ecx
15910     # . epilogue
15911     89/<- %esp 5/r32/ebp
15912     5d/pop-to-ebp
15913     c3/return
15914 
15915 emit-subx-var-def:  # out: (addr buffered-file), stmt: (addr stmt)
15916     # . prologue
15917     55/push-ebp
15918     89/<- %ebp 4/r32/esp
15919     # . save registers
15920     50/push-eax
15921     51/push-ecx
15922     52/push-edx
15923     # eax = stmt
15924     8b/-> *(ebp+0xc) 0/r32/eax
15925     # var v/ecx: (addr var)
15926     (lookup *(eax+4) *(eax+8))  # Vardef-var Vardef-var => eax
15927     89/<- %ecx 0/r32/eax
15928     # v->block-depth = *Curr-block-depth
15929     8b/-> *Curr-block-depth 0/r32/eax
15930     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
15931     # var n/edx: int = size-of(stmt->var)
15932     (size-of %ecx)  # => eax
15933     89/<- %edx 0/r32/eax
15934     # *Curr-local-stack-offset -= n
15935     29/subtract-from *Curr-local-stack-offset 2/r32/edx
15936     # v->offset = *Curr-local-stack-offset
15937     8b/-> *Curr-local-stack-offset 0/r32/eax
15938     89/<- *(ecx+0x14) 0/r32/eax  # Var-offset
15939     # if v is an array, do something special to initialize it
15940     {
15941       (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
15942       (is-mu-array? %eax)  # => eax
15943       3d/compare-eax-and 0/imm32/false
15944       0f 84/jump-if-= break/disp32
15945       # var array-size-without-size/edx: int = n-4
15946       81 5/subop/subtract %edx 4/imm32
15947       #
15948       (emit-array-data-initialization *(ebp+8) %edx)
15949       e9/jump $emit-subx-var-def:end/disp32
15950     }
15951     # another special-case for initializing streams
15952     # a stream is an array with 2 extra pointers
15953     {
15954       (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
15955       (is-mu-stream? %eax)  # => eax
15956       3d/compare-eax-and 0/imm32/false
15957       0f 84/jump-if-= break/disp32
15958       # var array-size-without-size/edx: int = n-12
15959       81 5/subop/subtract %edx 0xc/imm32
15960       (emit-array-data-initialization *(ebp+8) %edx)
15961       # emit read and write pointers
15962       (emit-indent *(ebp+8) *Curr-block-depth)
15963       (write-buffered *(ebp+8) "68/push 0/imm32\n")
15964       (emit-indent *(ebp+8) *Curr-block-depth)
15965       (write-buffered *(ebp+8) "68/push 0/imm32\n")
15966       #
15967       eb/jump $emit-subx-var-def:end/disp8
15968     }
15969     # while n > 0
15970     {
15971       81 7/subop/compare %edx 0/imm32
15972       7e/jump-if-<= break/disp8
15973       (emit-indent *(ebp+8) *Curr-block-depth)
15974       (write-buffered *(ebp+8) "68/push 0/imm32\n")
15975       # n -= 4
15976       81 5/subop/subtract %edx 4/imm32
15977       #
15978       eb/jump loop/disp8
15979     }
15980 $emit-subx-var-def:end:
15981     # . restore registers
15982     5a/pop-to-edx
15983     59/pop-to-ecx
15984     58/pop-to-eax
15985     # . epilogue
15986     89/<- %esp 5/r32/ebp
15987     5d/pop-to-ebp
15988     c3/return
15989 
15990 emit-array-data-initialization:  # out: (addr buffered-file), n: int
15991     # . prologue
15992     55/push-ebp
15993     89/<- %ebp 4/r32/esp
15994     #
15995     (emit-indent *(ebp+8) *Curr-block-depth)
15996     (write-buffered *(ebp+8) "(push-n-zero-bytes ")
15997     (write-int32-hex-buffered *(ebp+8) *(ebp+0xc))
15998     (write-buffered *(ebp+8) ")\n")
15999     (emit-indent *(ebp+8) *Curr-block-depth)
16000     (write-buffered *(ebp+8) "68/push ")
16001     (write-int32-hex-buffered *(ebp+8) *(ebp+0xc))
16002     (write-buffered *(ebp+8) "/imm32\n")
16003 $emit-array-data-initialization:end:
16004     # . epilogue
16005     89/<- %esp 5/r32/ebp
16006     5d/pop-to-ebp
16007     c3/return
16008 
16009 emit-subx-stmt:  # out: (addr buffered-file), stmt: (addr stmt), primitives: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
16010     # . prologue
16011     55/push-ebp
16012     89/<- %ebp 4/r32/esp
16013     # . save registers
16014     50/push-eax
16015     51/push-ecx
16016     # - some special-case primitives that don't actually use the 'primitives' data structure
16017     # var op/ecx: (addr array byte) = lookup(stmt->operation)
16018     8b/-> *(ebp+0xc) 1/r32/ecx
16019     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
16020     89/<- %ecx 0/r32/eax
16021     # array size
16022     {
16023       # if (!string-equal?(stmt->operation, "length")) break
16024       (string-equal? %ecx "length")  # => eax
16025       3d/compare-eax-and 0/imm32
16026       0f 84/jump-if-= break/disp32
16027       (translate-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16028       e9/jump $emit-subx-stmt:end/disp32
16029     }
16030     # index into array
16031     {
16032       # if (!string-equal?(stmt->operation, "index")) break
16033       (string-equal? %ecx "index")  # => eax
16034       3d/compare-eax-and 0/imm32
16035       0f 84/jump-if-= break/disp32
16036       (translate-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16037       e9/jump $emit-subx-stmt:end/disp32
16038     }
16039     # compute-offset for index into array
16040     {
16041       # if (!string-equal?(stmt->operation, "compute-offset")) break
16042       (string-equal? %ecx "compute-offset")  # => eax
16043       3d/compare-eax-and 0/imm32
16044       0f 84/jump-if-= break/disp32
16045       (translate-mu-compute-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16046       e9/jump $emit-subx-stmt:end/disp32
16047     }
16048     # get field from record
16049     {
16050       # if (!string-equal?(stmt->operation, "get")) break
16051       (string-equal? %ecx "get")  # => eax
16052       3d/compare-eax-and 0/imm32
16053       0f 84/jump-if-= break/disp32
16054       (translate-mu-get-stmt *(ebp+8) *(ebp+0xc))
16055       e9/jump $emit-subx-stmt:end/disp32
16056     }
16057     # allocate scalar
16058     {
16059       # if (!string-equal?(stmt->operation, "allocate")) break
16060       (string-equal? %ecx "allocate")  # => eax
16061       3d/compare-eax-and 0/imm32
16062       0f 84/jump-if-= break/disp32
16063       (translate-mu-allocate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16064       e9/jump $emit-subx-stmt:end/disp32
16065     }
16066     # copy-object
16067     {
16068       # if (!string-equal?(stmt->operation, "copy-object")) break
16069       (string-equal? %ecx "copy-object")  # => eax
16070       3d/compare-eax-and 0/imm32
16071       0f 84/jump-if-= break/disp32
16072       (translate-mu-copy-object-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16073       e9/jump $emit-subx-stmt:end/disp32
16074     }
16075     # allocate array
16076     {
16077       # if (!string-equal?(stmt->operation, "populate")) break
16078       (string-equal? %ecx "populate")  # => eax
16079       3d/compare-eax-and 0/imm32
16080       0f 84/jump-if-= break/disp32
16081       (translate-mu-populate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16082       e9/jump $emit-subx-stmt:end/disp32
16083     }
16084     # allocate stream
16085     {
16086       # if (!string-equal?(stmt->operation, "populate-stream")) break
16087       (string-equal? %ecx "populate-stream")  # => eax
16088       3d/compare-eax-and 0/imm32
16089       0f 84/jump-if-= break/disp32
16090       (translate-mu-populate-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16091       e9/jump $emit-subx-stmt:end/disp32
16092     }
16093     # read from stream
16094     {
16095       # if (!string-equal?(stmt->operation, "read-from-stream")) break
16096       (string-equal? %ecx "read-from-stream")  # => eax
16097       3d/compare-eax-and 0/imm32
16098       0f 84/jump-if-= break/disp32
16099       (translate-mu-read-from-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16100       e9/jump $emit-subx-stmt:end/disp32
16101     }
16102     # write to stream
16103     {
16104       # if (!string-equal?(stmt->operation, "write-to-stream")) break
16105       (string-equal? %ecx "write-to-stream")  # => eax
16106       3d/compare-eax-and 0/imm32
16107       0f 84/jump-if-= break/disp32
16108       (translate-mu-write-to-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16109       e9/jump $emit-subx-stmt:end/disp32
16110     }
16111     # - if stmt matches a primitive, emit it
16112     {
16113 $emit-subx-stmt:check-for-primitive:
16114       # var curr/eax: (addr primitive)
16115       (find-matching-primitive *(ebp+0x10) *(ebp+0xc))  # primitives, stmt => eax
16116       3d/compare-eax-and 0/imm32
16117       74/jump-if-= break/disp8
16118 $emit-subx-stmt:primitive:
16119       (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax)  # out, stmt, curr
16120       e9/jump $emit-subx-stmt:end/disp32
16121     }
16122     # - otherwise emit a call
16123     # TODO: type-checking
16124 $emit-subx-stmt:call:
16125     (emit-call *(ebp+8) *(ebp+0xc))
16126 $emit-subx-stmt:end:
16127     # . restore registers
16128     59/pop-to-ecx
16129     58/pop-to-eax
16130     # . epilogue
16131     89/<- %esp 5/r32/ebp
16132     5d/pop-to-ebp
16133     c3/return
16134 
16135 translate-mu-length-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
16136     # . prologue
16137     55/push-ebp
16138     89/<- %ebp 4/r32/esp
16139     # . save registers
16140     50/push-eax
16141     51/push-ecx
16142     52/push-edx
16143     53/push-ebx
16144     56/push-esi
16145     # esi = stmt
16146     8b/-> *(ebp+0xc) 6/r32/esi
16147     # var base/ebx: (addr var) = stmt->inouts[0]->value
16148     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16149     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16150     89/<- %ebx 0/r32/eax
16151     # var elemsize/ecx: int = array-element-size(base)
16152     (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
16153     89/<- %ecx 0/r32/eax
16154     # var outreg/edx: (addr array byte) = stmt->outputs[0]->value->register
16155     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
16156     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16157     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
16158     89/<- %edx 0/r32/eax
16159     # if elemsize == 1
16160     {
16161       81 7/subop/compare %ecx 1/imm32
16162       75/jump-if-!= break/disp8
16163 $translate-mu-length-stmt:size-1:
16164       (emit-save-size-to *(ebp+8) %ebx %edx)
16165       e9/jump $translate-mu-length-stmt:end/disp32
16166     }
16167     # if elemsize is a power of 2 less than 256
16168     {
16169       (power-of-2? %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
16170       3d/compare-eax-and 0/imm32/false
16171       74/jump-if-= break/disp8
16172       81 7/subop/compare %ecx 0xff/imm32
16173       7f/jump-if-> break/disp8
16174 $translate-mu-length-stmt:size-power-of-2:
16175       (emit-save-size-to *(ebp+8) %ebx %edx)
16176       (emit-divide-by-shift-right *(ebp+8) %edx %ecx)
16177       e9/jump $translate-mu-length-stmt:end/disp32
16178     }
16179     # otherwise, the complex case
16180     # . emit register spills
16181     {
16182 $translate-mu-length-stmt:complex:
16183       (string-equal? %edx "eax")  # => eax
16184       3d/compare-eax-and 0/imm32/false
16185       75/break-if-!= break/disp8
16186       (emit-indent *(ebp+8) *Curr-block-depth)
16187       (write-buffered *(ebp+8) "50/push-eax\n")
16188     }
16189     {
16190       (string-equal? %edx "ecx")  # => eax
16191       3d/compare-eax-and 0/imm32/false
16192       75/break-if-!= break/disp8
16193       (emit-indent *(ebp+8) *Curr-block-depth)
16194       (write-buffered *(ebp+8) "51/push-ecx\n")
16195     }
16196     {
16197       (string-equal? %edx "edx")  # => eax
16198       3d/compare-eax-and 0/imm32/false
16199       75/break-if-!= break/disp8
16200       (emit-indent *(ebp+8) *Curr-block-depth)
16201       (write-buffered *(ebp+8) "52/push-edx\n")
16202     }
16203     # .
16204     (emit-save-size-to *(ebp+8) %ebx "eax")
16205     (emit-indent *(ebp+8) *Curr-block-depth)
16206     (write-buffered *(ebp+8) "31/xor %edx 2/r32/edx\n")
16207     (emit-indent *(ebp+8) *Curr-block-depth)
16208     (write-buffered *(ebp+8) "b9/copy-to-ecx ")
16209     (write-int32-hex-buffered *(ebp+8) %ecx)
16210     (write-buffered *(ebp+8) "/imm32\n")
16211     (emit-indent *(ebp+8) *Curr-block-depth)
16212     (write-buffered *(ebp+8) "f7 7/subop/idiv-eax-edx-by %ecx\n")
16213     {
16214       (string-equal? %edx "eax")  # => eax
16215       3d/compare-eax-and 0/imm32/false
16216       75/break-if-!= break/disp8
16217       (emit-indent *(ebp+8) *Curr-block-depth)
16218       (write-buffered *(ebp+8) "89/<- %")
16219       (write-buffered *(ebp+8) %edx)
16220       (write-buffered *(ebp+8) " 0/r32/eax\n")
16221     }
16222     # . emit register restores
16223     {
16224       (string-equal? %edx "edx")  # => eax
16225       3d/compare-eax-and 0/imm32/false
16226       75/break-if-!= break/disp8
16227       (emit-indent *(ebp+8) *Curr-block-depth)
16228       (write-buffered *(ebp+8) "5a/pop-to-edx\n")
16229     }
16230     {
16231       (string-equal? %edx "ecx")  # => eax
16232       3d/compare-eax-and 0/imm32/false
16233       75/break-if-!= break/disp8
16234       (emit-indent *(ebp+8) *Curr-block-depth)
16235       (write-buffered *(ebp+8) "59/pop-to-ecx\n")
16236     }
16237     {
16238       (string-equal? %edx "eax")  # => eax
16239       3d/compare-eax-and 0/imm32/false
16240       75/break-if-!= break/disp8
16241       (emit-indent *(ebp+8) *Curr-block-depth)
16242       (write-buffered *(ebp+8) "58/pop-to-eax\n")
16243     }
16244 $translate-mu-length-stmt:end:
16245     # . restore registers
16246     5e/pop-to-esi
16247     5b/pop-to-ebx
16248     5a/pop-to-edx
16249     59/pop-to-ecx
16250     58/pop-to-eax
16251     # . epilogue
16252     89/<- %esp 5/r32/ebp
16253     5d/pop-to-ebp
16254     c3/return
16255 
16256 array-element-size:  # arr: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
16257     # . prologue
16258     55/push-ebp
16259     89/<- %ebp 4/r32/esp
16260     #
16261     (array-element-type-id *(ebp+8) *(ebp+0xc) *(ebp+0x10))  # => eax
16262     (size-of-type-id-as-array-element %eax)  # => eax
16263 $array-element-size:end:
16264     # . epilogue
16265     89/<- %esp 5/r32/ebp
16266     5d/pop-to-ebp
16267     c3/return
16268 
16269 array-element-type-id:  # v: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: type-id
16270     # precondition: n is positive
16271     # . prologue
16272     55/push-ebp
16273     89/<- %ebp 4/r32/esp
16274     #
16275     8b/-> *(ebp+8) 0/r32/eax
16276     # var t/eax: (addr type-tree)
16277     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
16278     # if t == 0 abort
16279     3d/compare-eax-with 0/imm32
16280     0f 84/jump-if-== $array-element-type-id:error0/disp32
16281     # if t->is-atom? abort
16282     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
16283     0f 85/jump-if-!= $array-element-type-id:error1/disp32
16284     # if (t->left == addr) t = t->right
16285     {
16286       50/push-eax
16287       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
16288       (is-simple-mu-type? %eax 2)  # addr => eax
16289       3d/compare-eax-with 0/imm32/false
16290       58/pop-to-eax
16291       74/jump-if-= break/disp8
16292 $array-element-type-id:skip-addr:
16293       (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
16294     }
16295     # if t == 0 abort
16296     3d/compare-eax-with 0/imm32
16297     0f 84/jump-if-= $array-element-type-id:error2/disp32
16298     # if t->is-atom? abort
16299     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
16300     0f 85/jump-if-!= $array-element-type-id:error2/disp32
16301     # if t->left != array abort
16302     {
16303       50/push-eax
16304       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
16305       (is-simple-mu-type? %eax 3)  # array => eax
16306       3d/compare-eax-with 0/imm32/false
16307       58/pop-to-eax
16308 $array-element-type-id:no-array:
16309       0f 84/jump-if-= $array-element-type-id:error2/disp32
16310     }
16311 $array-element-type-id:skip-array:
16312     # t = t->right
16313     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
16314     # if t == 0 abort
16315     3d/compare-eax-with 0/imm32
16316     0f 84/jump-if-= $array-element-type-id:error2/disp32
16317     # if t->is-atom? abort
16318     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
16319     0f 85/jump-if-!= $array-element-type-id:error2/disp32
16320     # return t->left->value
16321     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
16322     8b/-> *(eax+4) 0/r32/eax  # Type-tree-value
16323 $array-element-type-id:end:
16324     # . epilogue
16325     89/<- %esp 5/r32/ebp
16326     5d/pop-to-ebp
16327     c3/return
16328 
16329 $array-element-type-id:error0:
16330     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
16331     50/push-eax
16332     8b/-> *(ebp+8) 0/r32/eax
16333     (lookup *eax *(eax+4))  # Var-name Var-name => eax
16334     (write-buffered *(ebp+0xc) %eax)
16335     58/pop-to-eax
16336     (write-buffered *(ebp+0xc) "' has no type\n")
16337     (flush *(ebp+0xc))
16338     (stop *(ebp+0x10) 1)
16339     # never gets here
16340 
16341 $array-element-type-id:error1:
16342     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
16343     50/push-eax
16344     8b/-> *(ebp+8) 0/r32/eax
16345     (lookup *eax *(eax+4))  # Var-name Var-name => eax
16346     (write-buffered *(ebp+0xc) %eax)
16347     58/pop-to-eax
16348     (write-buffered *(ebp+0xc) "' has atomic type ")
16349     (write-int32-hex-buffered *(ebp+0xc) *(eax+4))  # Type-tree-value
16350     (write-buffered *(ebp+0xc) Newline)
16351     (flush *(ebp+0xc))
16352     (stop *(ebp+0x10) 1)
16353     # never gets here
16354 
16355 $array-element-type-id:error2:
16356     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
16357     50/push-eax
16358     8b/-> *(ebp+8) 0/r32/eax
16359     (lookup *eax *(eax+4))  # Var-name Var-name => eax
16360     (write-buffered *(ebp+0xc) %eax)
16361     58/pop-to-eax
16362     (write-buffered *(ebp+0xc) "' has non-array type\n")
16363     (flush *(ebp+0xc))
16364     (stop *(ebp+0x10) 1)
16365     # never gets here
16366 
16367 size-of-type-id-as-array-element:  # t: type-id -> result/eax: int
16368     # . prologue
16369     55/push-ebp
16370     89/<- %ebp 4/r32/esp
16371     # eax = t
16372     8b/-> *(ebp+8) 0/r32/eax
16373     # if t is 'byte', size is 1
16374     3d/compare-eax-and 8/imm32/byte
16375     {
16376       75/jump-if-!= break/disp8
16377       b8/copy-to-eax 1/imm32
16378       eb/jump $size-of-type-id-as-array-element:end/disp8
16379     }
16380     # otherwise proceed as usual
16381     (size-of-type-id %eax)  # => eax
16382 $size-of-type-id-as-array-element:end:
16383     # . epilogue
16384     89/<- %esp 5/r32/ebp
16385     5d/pop-to-ebp
16386     c3/return
16387 
16388 emit-save-size-to:  # out: (addr buffered-file), base: (addr var), outreg: (addr array byte)
16389     # . prologue
16390     55/push-ebp
16391     89/<- %ebp 4/r32/esp
16392     # . save registers
16393     50/push-eax
16394     53/push-ebx
16395     # ebx = base
16396     8b/-> *(ebp+0xc) 3/r32/ebx
16397     (emit-indent *(ebp+8) *Curr-block-depth)
16398     (write-buffered *(ebp+8) "8b/-> *")
16399     # if base is an (addr array ...) in a register
16400     {
16401       81 7/subop/compare *(ebx+0x18)) 0/imm32  # Var-register
16402       74/jump-if-= break/disp8
16403 $emit-save-size-to:emit-base-from-register:
16404       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
16405       (write-buffered *(ebp+8) %eax)
16406       eb/jump $emit-save-size-to:emit-output/disp8
16407     }
16408     # otherwise if base is an (array ...) on the stack
16409     {
16410       81 7/subop/compare *(ebx+0x14)) 0/imm32  # Var-offset
16411       74/jump-if-= break/disp8
16412 $emit-save-size-to:emit-base-from-stack:
16413       (write-buffered *(ebp+8) "(ebp+")
16414       (write-int32-hex-buffered *(ebp+8) *(ebx+0x14))  # Var-offset
16415       (write-buffered *(ebp+8) ")")
16416     }
16417 $emit-save-size-to:emit-output:
16418     (write-buffered *(ebp+8) " ")
16419     (get Mu-registers *(ebp+0x10) 0xc "Mu-registers")  # => eax
16420     (write-int32-hex-buffered *(ebp+8) *eax)
16421     (write-buffered *(ebp+8) "/r32\n")
16422 $emit-save-size-to:end:
16423     # . restore registers
16424     5b/pop-to-ebx
16425     58/pop-to-eax
16426     # . epilogue
16427     89/<- %esp 5/r32/ebp
16428     5d/pop-to-ebp
16429     c3/return
16430 
16431 emit-divide-by-shift-right:  # out: (addr buffered-file), reg: (addr array byte), size: int
16432     # . prologue
16433     55/push-ebp
16434     89/<- %ebp 4/r32/esp
16435     # . save registers
16436     50/push-eax
16437     #
16438     (emit-indent *(ebp+8) *Curr-block-depth)
16439     (write-buffered *(ebp+8) "c1/shift 5/subop/>> %")
16440     (write-buffered *(ebp+8) *(ebp+0xc))
16441     (write-buffered *(ebp+8) Space)
16442     (num-shift-rights *(ebp+0x10))  # => eax
16443     (write-int32-hex-buffered *(ebp+8) %eax)
16444     (write-buffered *(ebp+8) "/imm8\n")
16445 $emit-divide-by-shift-right:end:
16446     # . restore registers
16447     58/pop-to-eax
16448     # . epilogue
16449     89/<- %esp 5/r32/ebp
16450     5d/pop-to-ebp
16451     c3/return
16452 
16453 translate-mu-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
16454     # . prologue
16455     55/push-ebp
16456     89/<- %ebp 4/r32/esp
16457     # . save registers
16458     51/push-ecx
16459     # ecx = stmt
16460     8b/-> *(ebp+0xc) 1/r32/ecx
16461     # var base/ecx: (addr var) = stmt->inouts[0]
16462     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16463     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16464     89/<- %ecx 0/r32/eax
16465     # if (var->register) do one thing
16466     {
16467       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
16468       74/jump-if-= break/disp8
16469       # TODO: ensure there's no dereference
16470       (translate-mu-index-stmt-with-array-in-register *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
16471       eb/jump $translate-mu-index-stmt:end/disp8
16472     }
16473     # if (var->offset) do a different thing
16474     {
16475       81 7/subop/compare *(ecx+0x14) 0/imm32  # Var-offset
16476       74/jump-if-= break/disp8
16477       # TODO: ensure there's no dereference
16478       (translate-mu-index-stmt-with-array-on-stack *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
16479       eb/jump $translate-mu-index-stmt:end/disp8
16480     }
16481 $translate-mu-index-stmt:end:
16482     # . restore registers
16483     59/pop-to-ecx
16484     # . epilogue
16485     89/<- %esp 5/r32/ebp
16486     5d/pop-to-ebp
16487     c3/return
16488 
16489 $translate-mu-index-stmt-with-array:error1:
16490     (write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input must either lie in a register or be a literal\n")
16491     (flush *(ebp+0x10))
16492     (stop *(ebp+0x14) 1)
16493     # never gets here
16494 
16495 $translate-mu-index-stmt-with-array:error2:
16496     (write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input when in a register must be an int or offset\n")
16497     (flush *(ebp+0x10))
16498     (stop *(ebp+0x14) 1)
16499     # never gets here
16500 
16501 translate-mu-index-stmt-with-array-in-register:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
16502     # . prologue
16503     55/push-ebp
16504     89/<- %ebp 4/r32/esp
16505     # . save registers
16506     50/push-eax
16507     51/push-ecx
16508     52/push-edx
16509     53/push-ebx
16510     #
16511     (emit-indent *(ebp+8) *Curr-block-depth)
16512     (write-buffered *(ebp+8) "8d/copy-address *(")
16513     # TODO: ensure inouts[0] is in a register and not dereferenced
16514 $translate-mu-index-stmt-with-array-in-register:emit-base:
16515     # ecx = stmt
16516     8b/-> *(ebp+0xc) 1/r32/ecx
16517     # var base/ebx: (addr var) = inouts[0]
16518     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16519     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16520     89/<- %ebx 0/r32/eax
16521     # print base->register " + "
16522     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
16523     (write-buffered *(ebp+8) %eax)
16524     (write-buffered *(ebp+8) " + ")
16525     # var index/edx: (addr var) = inouts[1]
16526     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16527     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
16528     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16529     89/<- %edx 0/r32/eax
16530     # if index->register
16531     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
16532     {
16533       0f 84/jump-if-= break/disp32
16534 $translate-mu-index-stmt-with-array-in-register:emit-register-index:
16535       # if index is an int
16536       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
16537       (is-simple-mu-type? %eax 1)  # int => eax
16538       3d/compare-eax-and 0/imm32/false
16539       {
16540         0f 84/jump-if-= break/disp32
16541 $translate-mu-index-stmt-with-array-in-register:emit-int-register-index:
16542         # print index->register "<<" log2(array-element-size(base)) " + 4) "
16543         # . index->register "<<"
16544         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
16545         (write-buffered *(ebp+8) %eax)
16546         (write-buffered *(ebp+8) "<<")
16547         # . log2(array-element-size(base->type))
16548         # TODO: ensure size is a power of 2
16549         (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
16550         (num-shift-rights %eax)  # => eax
16551         (write-int32-hex-buffered *(ebp+8) %eax)
16552         e9/jump $translate-mu-index-stmt-with-array-in-register:emit-register-index-done/disp32
16553       }
16554       # if index->type is any other atom, abort
16555       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
16556       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
16557       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
16558       # if index has type (offset ...)
16559       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
16560       (is-simple-mu-type? %eax 7)  # => eax
16561       3d/compare-eax-and 0/imm32/false
16562       {
16563         0f 84/jump-if-= break/disp32
16564         # print index->register
16565 $translate-mu-index-stmt-with-array-in-register:emit-offset-register-index:
16566         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
16567         (write-buffered *(ebp+8) %eax)
16568       }
16569 $translate-mu-index-stmt-with-array-in-register:emit-register-index-done:
16570       (write-buffered *(ebp+8) " + 4) ")
16571       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
16572     }
16573     # otherwise if index is a literal
16574     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
16575     (is-simple-mu-type? %eax 0)  # => eax
16576     3d/compare-eax-and 0/imm32/false
16577     {
16578       0f 84/jump-if-= break/disp32
16579 $translate-mu-index-stmt-with-array-in-register:emit-literal-index:
16580       # var index-value/edx: int = parse-hex-int(index->name)
16581       (lookup *edx *(edx+4))  # Var-name Var-name => eax
16582       (parse-hex-int %eax)  # => eax
16583       89/<- %edx 0/r32/eax
16584       # offset = idx-value * array-element-size(base->type)
16585       (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
16586       f7 4/subop/multiply-into-edx-eax %edx  # clobbers edx
16587       # offset += 4 for array size
16588       05/add-to-eax 4/imm32
16589       # TODO: check edx for overflow
16590       # print offset
16591       (write-int32-hex-buffered *(ebp+8) %eax)
16592       (write-buffered *(ebp+8) ") ")
16593       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
16594     }
16595     # otherwise abort
16596     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
16597 $translate-mu-index-stmt-with-array-in-register:emit-output:
16598     # outputs[0] "/r32"
16599     8b/-> *(ebp+0xc) 1/r32/ecx
16600     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
16601     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16602     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
16603     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
16604     (write-int32-hex-buffered *(ebp+8) *eax)
16605     (write-buffered *(ebp+8) "/r32\n")
16606 $translate-mu-index-stmt-with-array-in-register:end:
16607     # . restore registers
16608     5b/pop-to-ebx
16609     5a/pop-to-edx
16610     59/pop-to-ecx
16611     58/pop-to-eax
16612     # . epilogue
16613     89/<- %esp 5/r32/ebp
16614     5d/pop-to-ebp
16615     c3/return
16616 
16617 translate-mu-index-stmt-with-array-on-stack:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
16618     # . prologue
16619     55/push-ebp
16620     89/<- %ebp 4/r32/esp
16621     # . save registers
16622     50/push-eax
16623     51/push-ecx
16624     52/push-edx
16625     53/push-ebx
16626     #
16627     (emit-indent *(ebp+8) *Curr-block-depth)
16628     (write-buffered *(ebp+8) "8d/copy-address *(ebp + ")
16629     # var curr/edx: (addr stmt-var) = lookup(stmt->inouts)
16630     8b/-> *(ebp+0xc) 0/r32/eax
16631     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16632     89/<- %edx 0/r32/eax
16633     # var base/ecx: (addr var) = lookup(curr->value)
16634     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16635     89/<- %ecx 0/r32/eax
16636     # var curr2/eax: (addr stmt-var) = lookup(curr->next)
16637     (lookup *(edx+8) *(edx+0xc))  # Stmt-var-next Stmt-var-next => eax
16638     # var index/edx: (handle var) = curr2->value
16639     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16640     89/<- %edx 0/r32/eax
16641     # if index->register
16642     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
16643     {
16644       0f 84/jump-if-= break/disp32
16645 $translate-mu-index-stmt-with-array-on-stack:emit-register-index:
16646       # if index is an int
16647       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
16648       (is-simple-mu-type? %eax 1)  # int => eax
16649       3d/compare-eax-and 0/imm32/false
16650       {
16651         0f 84/jump-if-= break/disp32
16652 $translate-mu-index-stmt-with-array-on-stack:emit-int-register-index:
16653         # print index->register "<<" log2(array-element-size(base)) " + " base->offset+4
16654         # . inouts[1]->register "<<"
16655         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
16656         (write-buffered *(ebp+8) %eax)
16657         (write-buffered *(ebp+8) "<<")
16658         # . log2(array-element-size(base))
16659         # TODO: ensure size is a power of 2
16660         (array-element-size %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
16661         (num-shift-rights %eax)  # => eax
16662         (write-int32-hex-buffered *(ebp+8) %eax)
16663         #
16664         (write-buffered *(ebp+8) " + ")
16665         #
16666         8b/-> *(ecx+0x14) 0/r32/eax  # Var-offset
16667         05/add-to-eax 4/imm32  # for array length
16668         (write-int32-hex-buffered *(ebp+8) %eax)
16669         e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done/disp32
16670       }
16671       # if index->type is any other atom, abort
16672       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
16673       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
16674       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
16675       # if index has type (offset ...)
16676       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
16677       (is-simple-mu-type? %eax 7)  # => eax
16678       3d/compare-eax-and 0/imm32/false
16679       {
16680         0f 84/jump-if-= break/disp32
16681         # print index->register
16682 $translate-mu-index-stmt-with-array-on-stack:emit-offset-register-index:
16683         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
16684         (write-buffered *(ebp+8) %eax)
16685       }
16686 $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done:
16687       (write-buffered *(ebp+8) ") ")
16688       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
16689     }
16690     # otherwise if index is a literal
16691     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
16692     (is-simple-mu-type? %eax 0)  # => eax
16693     3d/compare-eax-and 0/imm32/false
16694     {
16695       0f 84/jump-if-= break/disp32
16696 $translate-mu-index-stmt-with-array-on-stack:emit-literal-index:
16697       # var idx-value/edx: int = parse-hex-int(index->name)
16698       (lookup *edx *(edx+4))  # Var-name Var-name => eax
16699       (parse-hex-int %eax)  # Var-name => eax
16700       89/<- %edx 0/r32/eax
16701       # offset = idx-value * array-element-size(base)
16702       (array-element-size %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
16703       f7 4/subop/multiply-into-edx-eax %edx  # clobbers edx
16704       # offset += base->offset
16705       03/add *(ecx+0x14) 0/r32/eax  # Var-offset
16706       # offset += 4 for array size
16707       05/add-to-eax 4/imm32
16708       # TODO: check edx for overflow
16709       # print offset
16710       (write-int32-hex-buffered *(ebp+8) %eax)
16711       (write-buffered *(ebp+8) ") ")
16712       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
16713     }
16714     # otherwise abort
16715     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
16716 $translate-mu-index-stmt-with-array-on-stack:emit-output:
16717     # outputs[0] "/r32"
16718     8b/-> *(ebp+0xc) 0/r32/eax
16719     (lookup *(eax+0x14) *(eax+0x18))  # Stmt1-outputs Stmt1-outputs => eax
16720     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16721     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
16722     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
16723     (write-int32-hex-buffered *(ebp+8) *eax)
16724     (write-buffered *(ebp+8) "/r32\n")
16725 $translate-mu-index-stmt-with-array-on-stack:end:
16726     # . restore registers
16727     5b/pop-to-ebx
16728     5a/pop-to-edx
16729     59/pop-to-ecx
16730     58/pop-to-eax
16731     # . epilogue
16732     89/<- %esp 5/r32/ebp
16733     5d/pop-to-ebp
16734     c3/return
16735 
16736 translate-mu-compute-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
16737     # . prologue
16738     55/push-ebp
16739     89/<- %ebp 4/r32/esp
16740     # . save registers
16741     50/push-eax
16742     51/push-ecx
16743     52/push-edx
16744     53/push-ebx
16745     #
16746     (emit-indent *(ebp+8) *Curr-block-depth)
16747     (write-buffered *(ebp+8) "69/multiply")
16748     # ecx = stmt
16749     8b/-> *(ebp+0xc) 1/r32/ecx
16750     # var first-inout/ebx: (addr stmt-var) = stmt->inouts[0]
16751     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16752     89/<- %ebx 0/r32/eax
16753 $translate-mu-compute-index-stmt:emit-index:
16754     (lookup *(ebx+8) *(ebx+0xc))  # Stmt-var-next Stmt-var-next => eax
16755     (emit-subx-var-as-rm32 *(ebp+8) %eax)
16756     (write-buffered *(ebp+8) Space)
16757 $translate-mu-compute-index-stmt:emit-elem-size:
16758     # var base/ebx: (addr var)
16759     (lookup *ebx *(ebx+4))  # Stmt-var-value Stmt-var-value => eax
16760     89/<- %ebx 0/r32/eax
16761     # print array-element-size(base)
16762     (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
16763     (write-int32-hex-buffered *(ebp+8) %eax)
16764     (write-buffered *(ebp+8) "/imm32 ")
16765 $translate-mu-compute-index-stmt:emit-output:
16766     # outputs[0] "/r32"
16767     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
16768     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16769     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
16770     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
16771     (write-int32-hex-buffered *(ebp+8) *eax)
16772     (write-buffered *(ebp+8) "/r32\n")
16773 $translate-mu-compute-index-stmt:end:
16774     # . restore registers
16775     5b/pop-to-ebx
16776     5a/pop-to-edx
16777     59/pop-to-ecx
16778     58/pop-to-eax
16779     # . epilogue
16780     89/<- %esp 5/r32/ebp
16781     5d/pop-to-ebp
16782     c3/return
16783 
16784 translate-mu-get-stmt:  # out: (addr buffered-file), stmt: (addr stmt)
16785     # . prologue
16786     55/push-ebp
16787     89/<- %ebp 4/r32/esp
16788     # . save registers
16789     50/push-eax
16790     51/push-ecx
16791     52/push-edx
16792     #
16793     (emit-indent *(ebp+8) *Curr-block-depth)
16794     (write-buffered *(ebp+8) "8d/copy-address ")
16795     # ecx = stmt
16796     8b/-> *(ebp+0xc) 1/r32/ecx
16797     # var offset/edx: int = get offset of stmt
16798     (mu-get-offset %ecx)  # => eax
16799     89/<- %edx 0/r32/eax
16800     # var base/eax: (addr var) = stmt->inouts->value
16801     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16802     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16803     # if base is in a register
16804     81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
16805     {
16806       0f 84/jump-if-= break/disp32
16807 $translate-mu-get-stmt:emit-register-input:
16808       # emit "*(" base->register " + " offset ") "
16809       (write-buffered *(ebp+8) "*(")
16810       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
16811       (write-buffered *(ebp+8) %eax)
16812       (write-buffered *(ebp+8) " + ")
16813       (write-int32-hex-buffered *(ebp+8) %edx)
16814       (write-buffered *(ebp+8) ") ")
16815       e9/jump $translate-mu-get-stmt:emit-output/disp32
16816     }
16817     # otherwise base is on the stack
16818     {
16819 $translate-mu-get-stmt:emit-stack-input:
16820       # emit "*(ebp + " inouts[0]->stack-offset + offset ") "
16821       (write-buffered *(ebp+8) "*(ebp+")
16822       03/add *(eax+0x14) 2/r32/edx  # Var-offset
16823       (write-int32-hex-buffered *(ebp+8) %edx)
16824       (write-buffered *(ebp+8) ") ")
16825       eb/jump $translate-mu-get-stmt:emit-output/disp8
16826     }
16827 $translate-mu-get-stmt:emit-output:
16828     # var output/eax: (addr var) = stmt->outputs->value
16829     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
16830     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16831     # emit offset->register "/r32"
16832     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
16833     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
16834     (write-int32-hex-buffered *(ebp+8) *eax)
16835     (write-buffered *(ebp+8) "/r32\n")
16836 $translate-mu-get-stmt:end:
16837     # . restore registers
16838     5a/pop-to-edx
16839     59/pop-to-ecx
16840     58/pop-to-eax
16841     # . epilogue
16842     89/<- %esp 5/r32/ebp
16843     5d/pop-to-ebp
16844     c3/return
16845 
16846 translate-mu-copy-object-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
16847     # . prologue
16848     55/push-ebp
16849     89/<- %ebp 4/r32/esp
16850     # . save registers
16851     50/push-eax
16852     #
16853     (emit-indent *(ebp+8) *Curr-block-depth)
16854     (write-buffered *(ebp+8) "(copy-bytes")
16855     # eax = stmt
16856     8b/-> *(ebp+0xc) 0/r32/eax
16857     # var first-inout/eax: (addr stmt-var) = stmt->inouts[0]
16858     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16859     (emit-subx-call-operand *(ebp+8) %eax)
16860     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
16861     (emit-subx-call-operand *(ebp+8) %eax)
16862     (write-buffered *(ebp+8) Space)
16863     (addr-payload-size %eax *(ebp+0x10) *(ebp+0x14))  # => eax
16864     (write-int32-hex-buffered *(ebp+8) %eax)
16865     (write-buffered *(ebp+8) ")\n")
16866 $translate-mu-copy-object-stmt:end:
16867     # . restore registers
16868     58/pop-to-eax
16869     # . epilogue
16870     89/<- %esp 5/r32/ebp
16871     5d/pop-to-ebp
16872     c3/return
16873 
16874 translate-mu-allocate-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
16875     # . prologue
16876     55/push-ebp
16877     89/<- %ebp 4/r32/esp
16878     # . save registers
16879     50/push-eax
16880     56/push-esi
16881     57/push-edi
16882     # esi = stmt
16883     8b/-> *(ebp+0xc) 6/r32/esi
16884     # var target/edi: (addr stmt-var) = stmt->inouts[0]
16885     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16886     89/<- %edi 0/r32/eax
16887     #
16888     (emit-indent *(ebp+8) *Curr-block-depth)
16889     (write-buffered *(ebp+8) "(allocate Heap ")
16890     (addr-handle-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
16891     (write-int32-hex-buffered *(ebp+8) %eax)
16892     (emit-subx-call-operand *(ebp+8) %edi)
16893     (write-buffered *(ebp+8) ")\n")
16894 $translate-mu-allocate-stmt:end:
16895     # . restore registers
16896     5f/pop-to-edi
16897     5e/pop-to-esi
16898     58/pop-to-eax
16899     # . epilogue
16900     89/<- %esp 5/r32/ebp
16901     5d/pop-to-ebp
16902     c3/return
16903 
16904 addr-handle-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
16905     # . prologue
16906     55/push-ebp
16907     89/<- %ebp 4/r32/esp
16908     # var t/eax: (addr type-tree) = s->value->type
16909     8b/-> *(ebp+8) 0/r32/eax
16910     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16911     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
16912     # TODO: check eax != 0
16913     # TODO: check !t->is-atom?
16914     # TODO: check t->left == addr
16915     # t = t->right
16916 $addr-handle-payload-size:skip-addr:
16917     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
16918     # TODO: check eax != 0
16919     # TODO: check !t->is-atom?
16920     # TODO: check t->left == handle
16921     # t = t->right
16922 $addr-handle-payload-size:skip-handle:
16923     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
16924     # TODO: check eax != 0
16925     # if !t->is-atom? t = t->left
16926     81 7/subop/compare *eax 0/imm32/false
16927     {
16928       75/jump-if-!= break/disp8
16929       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
16930     }
16931     # TODO: check t->is-atom?
16932     # return size(t->value)
16933     (size-of-type-id *(eax+4))  # Type-tree-value => eax
16934 $addr-handle-payload-size:end:
16935     # . epilogue
16936     89/<- %esp 5/r32/ebp
16937     5d/pop-to-ebp
16938     c3/return
16939 
16940 addr-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
16941     # . prologue
16942     55/push-ebp
16943     89/<- %ebp 4/r32/esp
16944     # var t/eax: (addr type-tree) = s->value->type
16945     8b/-> *(ebp+8) 0/r32/eax
16946     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16947     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
16948     # TODO: check eax != 0
16949     # TODO: check !t->is-atom?
16950     # TODO: check t->left == addr
16951     # t = t->right
16952 $addr-payload-size:skip-addr:
16953     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
16954     # TODO: check eax != 0
16955     # if !t->is-atom? t = t->left
16956     81 7/subop/compare *eax 0/imm32/false
16957     {
16958       75/jump-if-!= break/disp8
16959       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
16960     }
16961     # TODO: check t->is-atom?
16962     # return size(t->value)
16963     (size-of-type-id *(eax+4))  # Type-tree-value => eax
16964 $addr-payload-size:end:
16965     # . epilogue
16966     89/<- %esp 5/r32/ebp
16967     5d/pop-to-ebp
16968     c3/return
16969 
16970 translate-mu-populate-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
16971     # . prologue
16972     55/push-ebp
16973     89/<- %ebp 4/r32/esp
16974     # . save registers
16975     50/push-eax
16976     51/push-ecx
16977     56/push-esi
16978     57/push-edi
16979     # esi = stmt
16980     8b/-> *(ebp+0xc) 6/r32/esi
16981     # var target/edi: (addr stmt-var) = stmt->inouts[0]
16982     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16983     89/<- %edi 0/r32/eax
16984     # var len/ecx: (addr stmt-var) = stmt->inouts[1]
16985     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
16986     89/<- %ecx 0/r32/eax
16987     #
16988     (emit-indent *(ebp+8) *Curr-block-depth)
16989     (write-buffered *(ebp+8) "(allocate-array2 Heap ")
16990     (addr-handle-array-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
16991     (write-int32-hex-buffered *(ebp+8) %eax)
16992     (emit-subx-call-operand *(ebp+8) %ecx)
16993     (emit-subx-call-operand *(ebp+8) %edi)
16994     (write-buffered *(ebp+8) ")\n")
16995 $translate-mu-populate-stmt:end:
16996     # . restore registers
16997     5f/pop-to-edi
16998     5e/pop-to-esi
16999     59/pop-to-ecx
17000     58/pop-to-eax
17001     # . epilogue
17002     89/<- %esp 5/r32/ebp
17003     5d/pop-to-ebp
17004     c3/return
17005 
17006 translate-mu-populate-stream-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
17007     # . prologue
17008     55/push-ebp
17009     89/<- %ebp 4/r32/esp
17010     # . save registers
17011     50/push-eax
17012     51/push-ecx
17013     56/push-esi
17014     57/push-edi
17015     # esi = stmt
17016     8b/-> *(ebp+0xc) 6/r32/esi
17017     # var target/edi: (addr stmt-var) = stmt->inouts[0]
17018     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17019     89/<- %edi 0/r32/eax
17020     # var len/ecx: (addr stmt-var) = stmt->inouts[1]
17021     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
17022     89/<- %ecx 0/r32/eax
17023     #
17024     (emit-indent *(ebp+8) *Curr-block-depth)
17025     (write-buffered *(ebp+8) "(new-stream Heap ")
17026     (addr-handle-stream-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
17027     (write-int32-hex-buffered *(ebp+8) %eax)
17028     (emit-subx-call-operand *(ebp+8) %ecx)
17029     (emit-subx-call-operand *(ebp+8) %edi)
17030     (write-buffered *(ebp+8) ")\n")
17031 $translate-mu-populate-stream-stmt:end:
17032     # . restore registers
17033     5f/pop-to-edi
17034     5e/pop-to-esi
17035     59/pop-to-ecx
17036     58/pop-to-eax
17037     # . epilogue
17038     89/<- %esp 5/r32/ebp
17039     5d/pop-to-ebp
17040     c3/return
17041 
17042 translate-mu-read-from-stream-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
17043     # . prologue
17044     55/push-ebp
17045     89/<- %ebp 4/r32/esp
17046     # . save registers
17047     50/push-eax
17048     51/push-ecx
17049     56/push-esi
17050     57/push-edi
17051     # esi = stmt
17052     8b/-> *(ebp+0xc) 6/r32/esi
17053     # var stream/ecx: (addr stmt-var) = stmt->inouts[0]
17054     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17055     89/<- %ecx 0/r32/eax
17056     # var target/edi: (addr stmt-var) = stmt->inouts[1]
17057     (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
17058     89/<- %edi 0/r32/eax
17059     #
17060     (emit-indent *(ebp+8) *Curr-block-depth)
17061     (write-buffered *(ebp+8) "(read-from-stream")
17062     (emit-subx-call-operand *(ebp+8) %ecx)
17063     (emit-subx-call-operand *(ebp+8) %edi)
17064     (write-buffered *(ebp+8) Space)
17065     (addr-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
17066     (write-int32-hex-buffered *(ebp+8) %eax)
17067     (write-buffered *(ebp+8) ")\n")
17068 $translate-mu-read-from-stream-stmt:end:
17069     # . restore registers
17070     5f/pop-to-edi
17071     5e/pop-to-esi
17072     59/pop-to-ecx
17073     58/pop-to-eax
17074     # . epilogue
17075     89/<- %esp 5/r32/ebp
17076     5d/pop-to-ebp
17077     c3/return
17078 
17079 translate-mu-write-to-stream-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
17080     # . prologue
17081     55/push-ebp
17082     89/<- %ebp 4/r32/esp
17083     # . save registers
17084     50/push-eax
17085     51/push-ecx
17086     56/push-esi
17087     57/push-edi
17088     # esi = stmt
17089     8b/-> *(ebp+0xc) 6/r32/esi
17090     # var stream/ecx: (addr stmt-var) = stmt->inouts[0]
17091     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17092     89/<- %ecx 0/r32/eax
17093     # var target/edi: (addr stmt-var) = stmt->inouts[1]
17094     (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
17095     89/<- %edi 0/r32/eax
17096     #
17097     (emit-indent *(ebp+8) *Curr-block-depth)
17098     (write-buffered *(ebp+8) "(write-to-stream")
17099     (emit-subx-call-operand *(ebp+8) %ecx)
17100     (flush *(ebp+8))
17101     (emit-subx-call-operand *(ebp+8) %edi)
17102     (flush *(ebp+8))
17103     (write-buffered *(ebp+8) Space)
17104     (flush *(ebp+8))
17105     (addr-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
17106     (write-int32-hex-buffered *(ebp+8) %eax)
17107     (write-buffered *(ebp+8) ")\n")
17108 $translate-mu-write-to-stream-stmt:end:
17109     # . restore registers
17110     5f/pop-to-edi
17111     5e/pop-to-esi
17112     59/pop-to-ecx
17113     58/pop-to-eax
17114     # . epilogue
17115     89/<- %esp 5/r32/ebp
17116     5d/pop-to-ebp
17117     c3/return
17118 
17119 addr-handle-array-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
17120     # . prologue
17121     55/push-ebp
17122     89/<- %ebp 4/r32/esp
17123     # var t/eax: (addr type-tree) = s->value->type
17124     8b/-> *(ebp+8) 0/r32/eax
17125     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17126     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
17127     # TODO: check eax != 0
17128     # TODO: check !t->is-atom?
17129     # TODO: check t->left == addr
17130     # t = t->right
17131 $addr-handle-array-payload-size:skip-addr:
17132     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17133     # TODO: check eax != 0
17134     # TODO: check !t->is-atom?
17135     # TODO: check t->left == handle
17136     # t = t->right
17137 $addr-handle-array-payload-size:skip-handle:
17138     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17139     # TODO: check eax != 0
17140     # TODO: check !t->is-atom?
17141     # TODO: check t->left == array
17142     # t = t->right
17143 $addr-handle-array-payload-size:skip-array:
17144     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17145     # TODO: check eax != 0
17146     # if !t->is-atom? t = t->left
17147     81 7/subop/compare *eax 0/imm32/false
17148     {
17149       75/jump-if-!= break/disp8
17150       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
17151     }
17152 $addr-handle-array-payload-size:compute-size:
17153     # TODO: check t->is-atom?
17154     # return size(t->value)
17155     (size-of-type-id-as-array-element *(eax+4))  # Type-tree-value => eax
17156 $addr-handle-array-payload-size:end:
17157     # . epilogue
17158     89/<- %esp 5/r32/ebp
17159     5d/pop-to-ebp
17160     c3/return
17161 
17162 addr-handle-stream-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
17163     # . prologue
17164     55/push-ebp
17165     89/<- %ebp 4/r32/esp
17166     # var t/eax: (addr type-tree) = s->value->type
17167     8b/-> *(ebp+8) 0/r32/eax
17168     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17169     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
17170     # TODO: check eax != 0
17171     # TODO: check !t->is-atom?
17172     # TODO: check t->left == addr
17173     # t = t->right
17174 $addr-handle-stream-payload-size:skip-addr:
17175     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17176     # TODO: check eax != 0
17177     # TODO: check !t->is-atom?
17178     # TODO: check t->left == handle
17179     # t = t->right
17180 $addr-handle-stream-payload-size:skip-handle:
17181     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17182     # TODO: check eax != 0
17183     # TODO: check !t->is-atom?
17184     # TODO: check t->left == stream
17185     # t = t->right
17186 $addr-handle-stream-payload-size:skip-stream:
17187     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17188     # TODO: check eax != 0
17189     # if !t->is-atom? t = t->left
17190     81 7/subop/compare *eax 0/imm32/false
17191     {
17192       75/jump-if-!= break/disp8
17193       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
17194     }
17195 $addr-handle-stream-payload-size:compute-size:
17196     # TODO: check t->is-atom?
17197     # return size(t->value)
17198     (size-of-type-id-as-array-element *(eax+4))  # Type-tree-value => eax
17199 $addr-handle-stream-payload-size:end:
17200     # . epilogue
17201     89/<- %esp 5/r32/ebp
17202     5d/pop-to-ebp
17203     c3/return
17204 
17205 power-of-2?:  # n: int, err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: boolean
17206     # precondition: n is positive
17207     # . prologue
17208     55/push-ebp
17209     89/<- %ebp 4/r32/esp
17210     # eax = n
17211     8b/-> *(ebp+8) 0/r32/eax
17212     # if (n < 0) abort
17213     3d/compare-eax-with 0/imm32
17214     0f 8c/jump-if-< $power-of-2?:abort/disp32
17215     # var tmp/eax: int = n-1
17216     48/decrement-eax
17217     # var tmp2/eax: int = n & tmp
17218     23/and-> *(ebp+8) 0/r32/eax
17219     # return (tmp2 == 0)
17220     3d/compare-eax-and 0/imm32
17221     0f 94/set-byte-if-= %al
17222     81 4/subop/and %eax 0xff/imm32
17223 $power-of-2?:end:
17224     # . epilogue
17225     89/<- %esp 5/r32/ebp
17226     5d/pop-to-ebp
17227     c3/return
17228 
17229 $power-of-2?:abort:
17230     (write-buffered *(ebp+0xc) "power-of-2?: negative number\n")
17231     (flush *(ebp+0xc))
17232     (stop *(ebp+0x10) 1)
17233     # never gets here
17234 
17235 num-shift-rights:  # n: int -> result/eax: int
17236     # precondition: n is a positive power of 2
17237     # . prologue
17238     55/push-ebp
17239     89/<- %ebp 4/r32/esp
17240     # . save registers
17241     51/push-ecx
17242     # var curr/ecx: int = n
17243     8b/-> *(ebp+8) 1/r32/ecx
17244     # result = 0
17245     b8/copy-to-eax 0/imm32
17246     {
17247       # if (curr <= 1) break
17248       81 7/subop/compare %ecx 1/imm32
17249       7e/jump-if-<= break/disp8
17250       40/increment-eax
17251       c1/shift 5/subop/arithmetic-right %ecx 1/imm8
17252       eb/jump loop/disp8
17253     }
17254 $num-shift-rights:end:
17255     # . restore registers
17256     59/pop-to-ecx
17257     # . epilogue
17258     89/<- %esp 5/r32/ebp
17259     5d/pop-to-ebp
17260     c3/return
17261 
17262 mu-get-offset:  # stmt: (addr stmt) -> result/eax: int
17263     # . prologue
17264     55/push-ebp
17265     89/<- %ebp 4/r32/esp
17266     # var second-inout/eax: (addr stmt-var) = stmt->inouts->next
17267     8b/-> *(ebp+8) 0/r32/eax
17268     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17269     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
17270     # var output-var/eax: (addr var) = second-inout->value
17271     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17272 #?     (write-buffered Stderr "mu-get-offset: ")
17273 #?     (write-int32-hex-buffered Stderr %eax)
17274 #?     (write-buffered Stderr " name: ")
17275 #?     50/push-eax
17276 #?     (lookup *eax *(eax+4))  # Var-name
17277 #?     (write-buffered Stderr %eax)
17278 #?     58/pop-to-eax
17279 #?     (write-buffered Stderr Newline)
17280 #?     (flush Stderr)
17281     # return output-var->stack-offset
17282     8b/-> *(eax+0x14) 0/r32/eax  # Var-offset
17283 #?     (write-buffered Stderr "=> ")
17284 #?     (write-int32-hex-buffered Stderr %eax)
17285 #?     (write-buffered Stderr Newline)
17286 #?     (flush Stderr)
17287 $emit-get-offset:end:
17288     # . epilogue
17289     89/<- %esp 5/r32/ebp
17290     5d/pop-to-ebp
17291     c3/return
17292 
17293 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)
17294     # . prologue
17295     55/push-ebp
17296     89/<- %ebp 4/r32/esp
17297     # . save registers
17298     50/push-eax
17299     51/push-ecx
17300     56/push-esi
17301     # esi = block
17302     8b/-> *(ebp+0xc) 6/r32/esi
17303     # block->var->block-depth = *Curr-block-depth
17304     (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
17305     8b/-> *Curr-block-depth 1/r32/ecx
17306     89/<- *(eax+0x10) 1/r32/ecx  # Var-block-depth
17307     # var stmts/eax: (addr list stmt) = lookup(block->statements)
17308     (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
17309     #
17310     {
17311 $emit-subx-block:check-empty:
17312       3d/compare-eax-and 0/imm32
17313       0f 84/jump-if-= break/disp32
17314       (emit-indent *(ebp+8) *Curr-block-depth)
17315       (write-buffered *(ebp+8) "{\n")
17316       # var v/ecx: (addr var) = lookup(block->var)
17317       (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
17318       89/<- %ecx 0/r32/eax
17319       #
17320       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
17321       (write-buffered *(ebp+8) %eax)
17322       (write-buffered *(ebp+8) ":loop:\n")
17323       ff 0/subop/increment *Curr-block-depth
17324       (push *(ebp+0x10) *(esi+0xc))  # Block-var
17325       (push *(ebp+0x10) *(esi+0x10))  # Block-var
17326       (push *(ebp+0x10) 0)  # false
17327       # emit block->statements
17328       (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
17329       (emit-subx-stmt-list *(ebp+8) %eax *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
17330       (pop *(ebp+0x10))  # => eax
17331       (pop *(ebp+0x10))  # => eax
17332       (pop *(ebp+0x10))  # => eax
17333       ff 1/subop/decrement *Curr-block-depth
17334       (emit-indent *(ebp+8) *Curr-block-depth)
17335       (write-buffered *(ebp+8) "}\n")
17336       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
17337       (write-buffered *(ebp+8) %eax)
17338       (write-buffered *(ebp+8) ":break:\n")
17339     }
17340 $emit-subx-block:end:
17341     # . restore registers
17342     5e/pop-to-esi
17343     59/pop-to-ecx
17344     58/pop-to-eax
17345     # . epilogue
17346     89/<- %esp 5/r32/ebp
17347     5d/pop-to-ebp
17348     c3/return
17349 
17350 # Primitives supported
17351 # See mu_instructions for a summary of this linked-list data structure.
17352 #
17353 # For each operation, put variants with hard-coded registers before flexible ones.
17354 #
17355 # Unfortunately, our restrictions on addresses require that various fields in
17356 # primitives be handles, which complicates these definitions.
17357 #   - we need to insert dummy fields all over the place for fake alloc-ids
17358 #   - we can't use our syntax sugar of quoted literals for string fields
17359 #
17360 # Fake alloc-ids are needed because our type definitions up top require
17361 # handles but it's clearer to statically allocate these long-lived objects.
17362 # Fake alloc-ids are perfectly safe, but they can't be reclaimed.
17363 #
17364 # Every 'object' below starts with a fake alloc-id. It may also contain other
17365 # fake alloc-ids for various handle fields.
17366 #
17367 # I think of objects starting with a fake alloc-id as having type 'payload'.
17368 # It's not really intended to be created dynamically; for that use `allocate`
17369 # as usual.
17370 #
17371 # Idea for a notation to simplify such definitions:
17372 #   _Primitive-increment-eax:  # (payload primitive)
17373 #     0x11/alloc-id:fake:payload
17374 #     0x11 @(0x11 "increment")  # name
17375 #     0 0                       # inouts
17376 #     0x11 @(0x11/payload
17377 #            0x11 @(0x11/payload  # List-value
17378 #                   0 0             # Var-name
17379 #                   0x11 @(0x11     # Var-type
17380 #                          1/is-atom
17381 #                          1/value 0/unused   # Type-tree-left
17382 #                          0 0                # Type-tree-right
17383 #                         )
17384 #                   1               # block-depth
17385 #                   0               # stack-offset
17386 #                   0x11 @(0x11 "eax")  # Var-register
17387 #                  )
17388 #            0 0)                 # List-next
17389 #     ...
17390 #     _Primitive-increment-ecx/imm32/next
17391 #   ...
17392 # Awfully complex and non-obvious. But also clearly signals there's something
17393 # to learn here, so may be worth trying.
17394 #
17395 # '@' is just an initial thought. Punctuation used so far in Mu: () * % # / "
17396 #
17397 # For now we'll continue to just use comments and manually ensure they stay up
17398 # to date.
17399 == data
17400 Primitives:  # (addr primitive)
17401 # - increment/decrement
17402 _Primitive-increment-eax:  # (addr primitive)
17403     # var/eax <- increment => 40/increment-eax
17404     0x11/imm32/alloc-id:fake
17405     _string-increment/imm32/name
17406     0/imm32/no-inouts
17407     0/imm32/no-inouts
17408     0x11/imm32/alloc-id:fake
17409     Single-int-var-in-eax/imm32/outputs
17410     0x11/imm32/alloc-id:fake
17411     _string_40_increment_eax/imm32/subx-name
17412     0/imm32/no-rm32
17413     0/imm32/no-r32
17414     0/imm32/no-imm32
17415     0/imm32/no-imm8
17416     0/imm32/no-disp32
17417     0/imm32/output-is-write-only
17418     0x11/imm32/alloc-id:fake
17419     _Primitive-increment-ecx/imm32/next
17420 _Primitive-increment-ecx:  # (payload primitive)
17421     0x11/imm32/alloc-id:fake:payload
17422     # var/ecx <- increment => 41/increment-ecx
17423     0x11/imm32/alloc-id:fake
17424     _string-increment/imm32/name
17425     0/imm32/no-inouts
17426     0/imm32/no-inouts
17427     0x11/imm32/alloc-id:fake
17428     Single-int-var-in-ecx/imm32/outputs
17429     0x11/imm32/alloc-id:fake
17430     _string_41_increment_ecx/imm32/subx-name
17431     0/imm32/no-rm32
17432     0/imm32/no-r32
17433     0/imm32/no-imm32
17434     0/imm32/no-imm8
17435     0/imm32/no-disp32
17436     0/imm32/output-is-write-only
17437     0x11/imm32/alloc-id:fake
17438     _Primitive-increment-edx/imm32/next
17439 _Primitive-increment-edx:  # (payload primitive)
17440     0x11/imm32/alloc-id:fake:payload
17441     # var/edx <- increment => 42/increment-edx
17442     0x11/imm32/alloc-id:fake
17443     _string-increment/imm32/name
17444     0/imm32/no-inouts
17445     0/imm32/no-inouts
17446     0x11/imm32/alloc-id:fake
17447     Single-int-var-in-edx/imm32/outputs
17448     0x11/imm32/alloc-id:fake
17449     _string_42_increment_edx/imm32/subx-name
17450     0/imm32/no-rm32
17451     0/imm32/no-r32
17452     0/imm32/no-imm32
17453     0/imm32/no-imm8
17454     0/imm32/no-disp32
17455     0/imm32/output-is-write-only
17456     0x11/imm32/alloc-id:fake
17457     _Primitive-increment-ebx/imm32/next
17458 _Primitive-increment-ebx:  # (payload primitive)
17459     0x11/imm32/alloc-id:fake:payload
17460     # var/ebx <- increment => 43/increment-ebx
17461     0x11/imm32/alloc-id:fake
17462     _string-increment/imm32/name
17463     0/imm32/no-inouts
17464     0/imm32/no-inouts
17465     0x11/imm32/alloc-id:fake
17466     Single-int-var-in-ebx/imm32/outputs
17467     0x11/imm32/alloc-id:fake
17468     _string_43_increment_ebx/imm32/subx-name
17469     0/imm32/no-rm32
17470     0/imm32/no-r32
17471     0/imm32/no-imm32
17472     0/imm32/no-imm8
17473     0/imm32/no-disp32
17474     0/imm32/output-is-write-only
17475     0x11/imm32/alloc-id:fake
17476     _Primitive-increment-esi/imm32/next
17477 _Primitive-increment-esi:  # (payload primitive)
17478     0x11/imm32/alloc-id:fake:payload
17479     # var/esi <- increment => 46/increment-esi
17480     0x11/imm32/alloc-id:fake
17481     _string-increment/imm32/name
17482     0/imm32/no-inouts
17483     0/imm32/no-inouts
17484     0x11/imm32/alloc-id:fake
17485     Single-int-var-in-esi/imm32/outputs
17486     0x11/imm32/alloc-id:fake
17487     _string_46_increment_esi/imm32/subx-name
17488     0/imm32/no-rm32
17489     0/imm32/no-r32
17490     0/imm32/no-imm32
17491     0/imm32/no-imm8
17492     0/imm32/no-disp32
17493     0/imm32/output-is-write-only
17494     0x11/imm32/alloc-id:fake
17495     _Primitive-increment-edi/imm32/next
17496 _Primitive-increment-edi:  # (payload primitive)
17497     0x11/imm32/alloc-id:fake:payload
17498     # var/edi <- increment => 47/increment-edi
17499     0x11/imm32/alloc-id:fake
17500     _string-increment/imm32/name
17501     0/imm32/no-inouts
17502     0/imm32/no-inouts
17503     0x11/imm32/alloc-id:fake
17504     Single-int-var-in-edi/imm32/outputs
17505     0x11/imm32/alloc-id:fake
17506     _string_47_increment_edi/imm32/subx-name
17507     0/imm32/no-rm32
17508     0/imm32/no-r32
17509     0/imm32/no-imm32
17510     0/imm32/no-imm8
17511     0/imm32/no-disp32
17512     0/imm32/output-is-write-only
17513     0x11/imm32/alloc-id:fake
17514     _Primitive-decrement-eax/imm32/next
17515 _Primitive-decrement-eax:  # (payload primitive)
17516     0x11/imm32/alloc-id:fake:payload
17517     # var/eax <- decrement => 48/decrement-eax
17518     0x11/imm32/alloc-id:fake
17519     _string-decrement/imm32/name
17520     0/imm32/no-inouts
17521     0/imm32/no-inouts
17522     0x11/imm32/alloc-id:fake
17523     Single-int-var-in-eax/imm32/outputs
17524     0x11/imm32/alloc-id:fake
17525     _string_48_decrement_eax/imm32/subx-name
17526     0/imm32/no-rm32
17527     0/imm32/no-r32
17528     0/imm32/no-imm32
17529     0/imm32/no-imm8
17530     0/imm32/no-disp32
17531     0/imm32/output-is-write-only
17532     0x11/imm32/alloc-id:fake
17533     _Primitive-decrement-ecx/imm32/next
17534 _Primitive-decrement-ecx:  # (payload primitive)
17535     0x11/imm32/alloc-id:fake:payload
17536     # var/ecx <- decrement => 49/decrement-ecx
17537     0x11/imm32/alloc-id:fake
17538     _string-decrement/imm32/name
17539     0/imm32/no-inouts
17540     0/imm32/no-inouts
17541     0x11/imm32/alloc-id:fake
17542     Single-int-var-in-ecx/imm32/outputs
17543     0x11/imm32/alloc-id:fake
17544     _string_49_decrement_ecx/imm32/subx-name
17545     0/imm32/no-rm32
17546     0/imm32/no-r32
17547     0/imm32/no-imm32
17548     0/imm32/no-imm8
17549     0/imm32/no-disp32
17550     0/imm32/output-is-write-only
17551     0x11/imm32/alloc-id:fake
17552     _Primitive-decrement-edx/imm32/next
17553 _Primitive-decrement-edx:  # (payload primitive)
17554     0x11/imm32/alloc-id:fake:payload
17555     # var/edx <- decrement => 4a/decrement-edx
17556     0x11/imm32/alloc-id:fake
17557     _string-decrement/imm32/name
17558     0/imm32/no-inouts
17559     0/imm32/no-inouts
17560     0x11/imm32/alloc-id:fake
17561     Single-int-var-in-edx/imm32/outputs
17562     0x11/imm32/alloc-id:fake
17563     _string_4a_decrement_edx/imm32/subx-name
17564     0/imm32/no-rm32
17565     0/imm32/no-r32
17566     0/imm32/no-imm32
17567     0/imm32/no-imm8
17568     0/imm32/no-disp32
17569     0/imm32/output-is-write-only
17570     0x11/imm32/alloc-id:fake
17571     _Primitive-decrement-ebx/imm32/next
17572 _Primitive-decrement-ebx:  # (payload primitive)
17573     0x11/imm32/alloc-id:fake:payload
17574     # var/ebx <- decrement => 4b/decrement-ebx
17575     0x11/imm32/alloc-id:fake
17576     _string-decrement/imm32/name
17577     0/imm32/no-inouts
17578     0/imm32/no-inouts
17579     0x11/imm32/alloc-id:fake
17580     Single-int-var-in-ebx/imm32/outputs
17581     0x11/imm32/alloc-id:fake
17582     _string_4b_decrement_ebx/imm32/subx-name
17583     0/imm32/no-rm32
17584     0/imm32/no-r32
17585     0/imm32/no-imm32
17586     0/imm32/no-imm8
17587     0/imm32/no-disp32
17588     0/imm32/output-is-write-only
17589     0x11/imm32/alloc-id:fake
17590     _Primitive-decrement-esi/imm32/next
17591 _Primitive-decrement-esi:  # (payload primitive)
17592     0x11/imm32/alloc-id:fake:payload
17593     # var/esi <- decrement => 4e/decrement-esi
17594     0x11/imm32/alloc-id:fake
17595     _string-decrement/imm32/name
17596     0/imm32/no-inouts
17597     0/imm32/no-inouts
17598     0x11/imm32/alloc-id:fake
17599     Single-int-var-in-esi/imm32/outputs
17600     0x11/imm32/alloc-id:fake
17601     _string_4e_decrement_esi/imm32/subx-name
17602     0/imm32/no-rm32
17603     0/imm32/no-r32
17604     0/imm32/no-imm32
17605     0/imm32/no-imm8
17606     0/imm32/no-disp32
17607     0/imm32/output-is-write-only
17608     0x11/imm32/alloc-id:fake
17609     _Primitive-decrement-edi/imm32/next
17610 _Primitive-decrement-edi:  # (payload primitive)
17611     0x11/imm32/alloc-id:fake:payload
17612     # var/edi <- decrement => 4f/decrement-edi
17613     0x11/imm32/alloc-id:fake
17614     _string-decrement/imm32/name
17615     0/imm32/no-inouts
17616     0/imm32/no-inouts
17617     0x11/imm32/alloc-id:fake
17618     Single-int-var-in-edi/imm32/outputs
17619     0x11/imm32/alloc-id:fake
17620     _string_4f_decrement_edi/imm32/subx-name
17621     0/imm32/no-rm32
17622     0/imm32/no-r32
17623     0/imm32/no-imm32
17624     0/imm32/no-imm8
17625     0/imm32/no-disp32
17626     0/imm32/output-is-write-only
17627     0x11/imm32/alloc-id:fake
17628     _Primitive-increment-mem/imm32/next
17629 _Primitive-increment-mem:  # (payload primitive)
17630     0x11/imm32/alloc-id:fake:payload
17631     # increment var => ff 0/subop/increment *(ebp+__)
17632     0x11/imm32/alloc-id:fake
17633     _string-increment/imm32/name
17634     0x11/imm32/alloc-id:fake
17635     Single-int-var-in-mem/imm32/inouts
17636     0/imm32/no-outputs
17637     0/imm32/no-outputs
17638     0x11/imm32/alloc-id:fake
17639     _string_ff_subop_increment/imm32/subx-name
17640     1/imm32/rm32-is-first-inout
17641     0/imm32/no-r32
17642     0/imm32/no-imm32
17643     0/imm32/no-imm8
17644     0/imm32/no-disp32
17645     0/imm32/output-is-write-only
17646     0x11/imm32/alloc-id:fake
17647     _Primitive-increment-reg/imm32/next
17648 _Primitive-increment-reg:  # (payload primitive)
17649     0x11/imm32/alloc-id:fake:payload
17650     # var/reg <- increment => ff 0/subop/increment %__
17651     0x11/imm32/alloc-id:fake
17652     _string-increment/imm32/name
17653     0/imm32/no-inouts
17654     0/imm32/no-inouts
17655     0x11/imm32/alloc-id:fake
17656     Single-int-var-in-some-register/imm32/outputs
17657     0x11/imm32/alloc-id:fake
17658     _string_ff_subop_increment/imm32/subx-name
17659     3/imm32/rm32-is-first-output
17660     0/imm32/no-r32
17661     0/imm32/no-imm32
17662     0/imm32/no-imm8
17663     0/imm32/no-disp32
17664     0/imm32/output-is-write-only
17665     0x11/imm32/alloc-id:fake
17666     _Primitive-decrement-mem/imm32/next
17667 _Primitive-decrement-mem:  # (payload primitive)
17668     0x11/imm32/alloc-id:fake:payload
17669     # decrement var => ff 1/subop/decrement *(ebp+__)
17670     0x11/imm32/alloc-id:fake
17671     _string-decrement/imm32/name
17672     0x11/imm32/alloc-id:fake
17673     Single-int-var-in-mem/imm32/inouts
17674     0/imm32/no-outputs
17675     0/imm32/no-outputs
17676     0x11/imm32/alloc-id:fake
17677     _string_ff_subop_decrement/imm32/subx-name
17678     1/imm32/rm32-is-first-inout
17679     0/imm32/no-r32
17680     0/imm32/no-imm32
17681     0/imm32/no-imm8
17682     0/imm32/no-disp32
17683     0/imm32/output-is-write-only
17684     0x11/imm32/alloc-id:fake
17685     _Primitive-decrement-reg/imm32/next
17686 _Primitive-decrement-reg:  # (payload primitive)
17687     0x11/imm32/alloc-id:fake:payload
17688     # var/reg <- decrement => ff 1/subop/decrement %__
17689     0x11/imm32/alloc-id:fake
17690     _string-decrement/imm32/name
17691     0/imm32/no-inouts
17692     0/imm32/no-inouts
17693     0x11/imm32/alloc-id:fake
17694     Single-int-var-in-some-register/imm32/outputs
17695     0x11/imm32/alloc-id:fake
17696     _string_ff_subop_decrement/imm32/subx-name
17697     3/imm32/rm32-is-first-output
17698     0/imm32/no-r32
17699     0/imm32/no-imm32
17700     0/imm32/no-imm8
17701     0/imm32/no-disp32
17702     0/imm32/output-is-write-only
17703     0x11/imm32/alloc-id:fake
17704     _Primitive-add-to-eax/imm32/next
17705 # - add
17706 _Primitive-add-to-eax:  # (payload primitive)
17707     0x11/imm32/alloc-id:fake:payload
17708     # var/eax <- add lit => 05/add-to-eax lit/imm32
17709     0x11/imm32/alloc-id:fake
17710     _string-add/imm32/name
17711     0x11/imm32/alloc-id:fake
17712     Single-lit-var/imm32/inouts
17713     0x11/imm32/alloc-id:fake
17714     Single-int-var-in-eax/imm32/outputs
17715     0x11/imm32/alloc-id:fake
17716     _string_05_add_to_eax/imm32/subx-name
17717     0/imm32/no-rm32
17718     0/imm32/no-r32
17719     1/imm32/imm32-is-first-inout
17720     0/imm32/no-imm8
17721     0/imm32/no-disp32
17722     0/imm32/output-is-write-only
17723     0x11/imm32/alloc-id:fake
17724     _Primitive-add-reg-to-reg/imm32/next
17725 _Primitive-add-reg-to-reg:  # (payload primitive)
17726     0x11/imm32/alloc-id:fake:payload
17727     # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32
17728     0x11/imm32/alloc-id:fake
17729     _string-add/imm32/name
17730     0x11/imm32/alloc-id:fake
17731     Single-int-var-in-some-register/imm32/inouts
17732     0x11/imm32/alloc-id:fake
17733     Single-int-var-in-some-register/imm32/outputs
17734     0x11/imm32/alloc-id:fake
17735     _string_01_add_to/imm32/subx-name
17736     3/imm32/rm32-is-first-output
17737     1/imm32/r32-is-first-inout
17738     0/imm32/no-imm32
17739     0/imm32/no-imm8
17740     0/imm32/no-disp32
17741     0/imm32/output-is-write-only
17742     0x11/imm32/alloc-id:fake
17743     _Primitive-add-reg-to-mem/imm32/next
17744 _Primitive-add-reg-to-mem:  # (payload primitive)
17745     0x11/imm32/alloc-id:fake:payload
17746     # add-to var1 var2/reg => 01/add-to var1 var2/r32
17747     0x11/imm32/alloc-id:fake
17748     _string-add-to/imm32/name
17749     0x11/imm32/alloc-id:fake
17750     Two-args-int-stack-int-reg/imm32/inouts
17751     0/imm32/no-outputs
17752     0/imm32/no-outputs
17753     0x11/imm32/alloc-id:fake
17754     _string_01_add_to/imm32/subx-name
17755     1/imm32/rm32-is-first-inout
17756     2/imm32/r32-is-second-inout
17757     0/imm32/no-imm32
17758     0/imm32/no-imm8
17759     0/imm32/no-disp32
17760     0/imm32/output-is-write-only
17761     0x11/imm32/alloc-id:fake
17762     _Primitive-add-mem-to-reg/imm32/next
17763 _Primitive-add-mem-to-reg:  # (payload primitive)
17764     0x11/imm32/alloc-id:fake:payload
17765     # var1/reg <- add var2 => 03/add var2/rm32 var1/r32
17766     0x11/imm32/alloc-id:fake
17767     _string-add/imm32/name
17768     0x11/imm32/alloc-id:fake
17769     Single-int-var-in-mem/imm32/inouts
17770     0x11/imm32/alloc-id:fake
17771     Single-int-var-in-some-register/imm32/outputs
17772     0x11/imm32/alloc-id:fake
17773     _string_03_add/imm32/subx-name
17774     1/imm32/rm32-is-first-inout
17775     3/imm32/r32-is-first-output
17776     0/imm32/no-imm32
17777     0/imm32/no-imm8
17778     0/imm32/no-disp32
17779     0/imm32/output-is-write-only
17780     0x11/imm32/alloc-id:fake
17781     _Primitive-add-lit-to-reg/imm32/next
17782 _Primitive-add-lit-to-reg:  # (payload primitive)
17783     0x11/imm32/alloc-id:fake:payload
17784     # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32
17785     0x11/imm32/alloc-id:fake
17786     _string-add/imm32/name
17787     0x11/imm32/alloc-id:fake
17788     Single-lit-var/imm32/inouts
17789     0x11/imm32/alloc-id:fake
17790     Single-int-var-in-some-register/imm32/outputs
17791     0x11/imm32/alloc-id:fake
17792     _string_81_subop_add/imm32/subx-name
17793     3/imm32/rm32-is-first-output
17794     0/imm32/no-r32
17795     1/imm32/imm32-is-first-inout
17796     0/imm32/no-imm8
17797     0/imm32/no-disp32
17798     0/imm32/output-is-write-only
17799     0x11/imm32/alloc-id:fake
17800     _Primitive-add-lit-to-mem/imm32/next
17801 _Primitive-add-lit-to-mem:  # (payload primitive)
17802     0x11/imm32/alloc-id:fake:payload
17803     # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32
17804     0x11/imm32/alloc-id:fake
17805     _string-add-to/imm32/name
17806     0x11/imm32/alloc-id:fake
17807     Int-var-and-literal/imm32/inouts
17808     0/imm32/no-outputs
17809     0/imm32/no-outputs
17810     0x11/imm32/alloc-id:fake
17811     _string_81_subop_add/imm32/subx-name
17812     1/imm32/rm32-is-first-inout
17813     0/imm32/no-r32
17814     2/imm32/imm32-is-second-inout
17815     0/imm32/no-imm8
17816     0/imm32/no-disp32
17817     0/imm32/output-is-write-only
17818     0x11/imm32/alloc-id:fake
17819     _Primitive-subtract-from-eax/imm32/next
17820 # - subtract
17821 _Primitive-subtract-from-eax:  # (payload primitive)
17822     0x11/imm32/alloc-id:fake:payload
17823     # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32
17824     0x11/imm32/alloc-id:fake
17825     _string-subtract/imm32/name
17826     0x11/imm32/alloc-id:fake
17827     Single-lit-var/imm32/inouts
17828     0x11/imm32/alloc-id:fake
17829     Single-int-var-in-eax/imm32/outputs
17830     0x11/imm32/alloc-id:fake
17831     _string_2d_subtract_from_eax/imm32/subx-name
17832     0/imm32/no-rm32
17833     0/imm32/no-r32
17834     1/imm32/imm32-is-first-inout
17835     0/imm32/no-imm8
17836     0/imm32/no-disp32
17837     0/imm32/output-is-write-only
17838     0x11/imm32/alloc-id:fake
17839     _Primitive-subtract-reg-from-reg/imm32/next
17840 _Primitive-subtract-reg-from-reg:  # (payload primitive)
17841     0x11/imm32/alloc-id:fake:payload
17842     # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32
17843     0x11/imm32/alloc-id:fake
17844     _string-subtract/imm32/name
17845     0x11/imm32/alloc-id:fake
17846     Single-int-var-in-some-register/imm32/inouts
17847     0x11/imm32/alloc-id:fake
17848     Single-int-var-in-some-register/imm32/outputs
17849     0x11/imm32/alloc-id:fake
17850     _string_29_subtract_from/imm32/subx-name
17851     3/imm32/rm32-is-first-output
17852     1/imm32/r32-is-first-inout
17853     0/imm32/no-imm32
17854     0/imm32/no-imm8
17855     0/imm32/no-disp32
17856     0/imm32/output-is-write-only
17857     0x11/imm32/alloc-id:fake
17858     _Primitive-subtract-reg-from-mem/imm32/next
17859 _Primitive-subtract-reg-from-mem:  # (payload primitive)
17860     0x11/imm32/alloc-id:fake:payload
17861     # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32
17862     0x11/imm32/alloc-id:fake
17863     _string-subtract-from/imm32/name
17864     0x11/imm32/alloc-id:fake
17865     Two-args-int-stack-int-reg/imm32/inouts
17866     0/imm32/no-outputs
17867     0/imm32/no-outputs
17868     0x11/imm32/alloc-id:fake
17869     _string_29_subtract_from/imm32/subx-name
17870     1/imm32/rm32-is-first-inout
17871     2/imm32/r32-is-second-inout
17872     0/imm32/no-imm32
17873     0/imm32/no-imm8
17874     0/imm32/no-disp32
17875     0/imm32/output-is-write-only
17876     0x11/imm32/alloc-id:fake
17877     _Primitive-subtract-mem-from-reg/imm32/next
17878 _Primitive-subtract-mem-from-reg:  # (payload primitive)
17879     0x11/imm32/alloc-id:fake:payload
17880     # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32
17881     0x11/imm32/alloc-id:fake
17882     _string-subtract/imm32/name
17883     0x11/imm32/alloc-id:fake
17884     Single-int-var-in-mem/imm32/inouts
17885     0x11/imm32/alloc-id:fake
17886     Single-int-var-in-some-register/imm32/outputs
17887     0x11/imm32/alloc-id:fake
17888     _string_2b_subtract/imm32/subx-name
17889     1/imm32/rm32-is-first-inout
17890     3/imm32/r32-is-first-output
17891     0/imm32/no-imm32
17892     0/imm32/no-imm8
17893     0/imm32/no-disp32
17894     0/imm32/output-is-write-only
17895     0x11/imm32/alloc-id:fake
17896     _Primitive-subtract-lit-from-reg/imm32/next
17897 _Primitive-subtract-lit-from-reg:  # (payload primitive)
17898     0x11/imm32/alloc-id:fake:payload
17899     # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32
17900     0x11/imm32/alloc-id:fake
17901     _string-subtract/imm32/name
17902     0x11/imm32/alloc-id:fake
17903     Single-lit-var/imm32/inouts
17904     0x11/imm32/alloc-id:fake
17905     Single-int-var-in-some-register/imm32/outputs
17906     0x11/imm32/alloc-id:fake
17907     _string_81_subop_subtract/imm32/subx-name
17908     3/imm32/rm32-is-first-output
17909     0/imm32/no-r32
17910     1/imm32/imm32-is-first-inout
17911     0/imm32/no-imm8
17912     0/imm32/no-disp32
17913     0/imm32/output-is-write-only
17914     0x11/imm32/alloc-id:fake
17915     _Primitive-subtract-lit-from-mem/imm32/next
17916 _Primitive-subtract-lit-from-mem:  # (payload primitive)
17917     0x11/imm32/alloc-id:fake:payload
17918     # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32
17919     0x11/imm32/alloc-id:fake
17920     _string-subtract-from/imm32/name
17921     0x11/imm32/alloc-id:fake
17922     Int-var-and-literal/imm32/inouts
17923     0/imm32/no-outputs
17924     0/imm32/no-outputs
17925     0x11/imm32/alloc-id:fake
17926     _string_81_subop_subtract/imm32/subx-name
17927     1/imm32/rm32-is-first-inout
17928     0/imm32/no-r32
17929     2/imm32/imm32-is-second-inout
17930     0/imm32/no-imm8
17931     0/imm32/no-disp32
17932     0/imm32/output-is-write-only
17933     0x11/imm32/alloc-id:fake
17934     _Primitive-and-with-eax/imm32/next
17935 # - and
17936 _Primitive-and-with-eax:  # (payload primitive)
17937     0x11/imm32/alloc-id:fake:payload
17938     # var/eax <- and lit => 25/and-with-eax lit/imm32
17939     0x11/imm32/alloc-id:fake
17940     _string-and/imm32/name
17941     0x11/imm32/alloc-id:fake
17942     Single-lit-var/imm32/inouts
17943     0x11/imm32/alloc-id:fake
17944     Single-int-var-in-eax/imm32/outputs
17945     0x11/imm32/alloc-id:fake
17946     _string_25_and_with_eax/imm32/subx-name
17947     0/imm32/no-rm32
17948     0/imm32/no-r32
17949     1/imm32/imm32-is-first-inout
17950     0/imm32/no-imm8
17951     0/imm32/no-disp32
17952     0/imm32/output-is-write-only
17953     0x11/imm32/alloc-id:fake
17954     _Primitive-and-reg-with-reg/imm32/next
17955 _Primitive-and-reg-with-reg:  # (payload primitive)
17956     0x11/imm32/alloc-id:fake:payload
17957     # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32
17958     0x11/imm32/alloc-id:fake
17959     _string-and/imm32/name
17960     0x11/imm32/alloc-id:fake
17961     Single-int-var-in-some-register/imm32/inouts
17962     0x11/imm32/alloc-id:fake
17963     Single-int-var-in-some-register/imm32/outputs
17964     0x11/imm32/alloc-id:fake
17965     _string_21_and_with/imm32/subx-name
17966     3/imm32/rm32-is-first-output
17967     1/imm32/r32-is-first-inout
17968     0/imm32/no-imm32
17969     0/imm32/no-imm8
17970     0/imm32/no-disp32
17971     0/imm32/output-is-write-only
17972     0x11/imm32/alloc-id:fake
17973     _Primitive-and-reg-with-mem/imm32/next
17974 _Primitive-and-reg-with-mem:  # (payload primitive)
17975     0x11/imm32/alloc-id:fake:payload
17976     # and-with var1 var2/reg => 21/and-with var1 var2/r32
17977     0x11/imm32/alloc-id:fake
17978     _string-and-with/imm32/name
17979     0x11/imm32/alloc-id:fake
17980     Two-args-int-stack-int-reg/imm32/inouts
17981     0/imm32/no-outputs
17982     0/imm32/no-outputs
17983     0x11/imm32/alloc-id:fake
17984     _string_21_and_with/imm32/subx-name
17985     1/imm32/rm32-is-first-inout
17986     2/imm32/r32-is-second-inout
17987     0/imm32/no-imm32
17988     0/imm32/no-imm8
17989     0/imm32/no-disp32
17990     0/imm32/output-is-write-only
17991     0x11/imm32/alloc-id:fake
17992     _Primitive-and-mem-with-reg/imm32/next
17993 _Primitive-and-mem-with-reg:  # (payload primitive)
17994     0x11/imm32/alloc-id:fake:payload
17995     # var1/reg <- and var2 => 23/and var2/rm32 var1/r32
17996     0x11/imm32/alloc-id:fake
17997     _string-and/imm32/name
17998     0x11/imm32/alloc-id:fake
17999     Single-int-var-in-mem/imm32/inouts
18000     0x11/imm32/alloc-id:fake
18001     Single-int-var-in-some-register/imm32/outputs
18002     0x11/imm32/alloc-id:fake
18003     _string_23_and/imm32/subx-name
18004     1/imm32/rm32-is-first-inout
18005     3/imm32/r32-is-first-output
18006     0/imm32/no-imm32
18007     0/imm32/no-imm8
18008     0/imm32/no-disp32
18009     0/imm32/output-is-write-only
18010     0x11/imm32/alloc-id:fake
18011     _Primitive-and-lit-with-reg/imm32/next
18012 _Primitive-and-lit-with-reg:  # (payload primitive)
18013     0x11/imm32/alloc-id:fake:payload
18014     # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32
18015     0x11/imm32/alloc-id:fake
18016     _string-and/imm32/name
18017     0x11/imm32/alloc-id:fake
18018     Single-lit-var/imm32/inouts
18019     0x11/imm32/alloc-id:fake
18020     Single-int-var-in-some-register/imm32/outputs
18021     0x11/imm32/alloc-id:fake
18022     _string_81_subop_and/imm32/subx-name
18023     3/imm32/rm32-is-first-output
18024     0/imm32/no-r32
18025     1/imm32/imm32-is-first-inout
18026     0/imm32/no-imm8
18027     0/imm32/no-disp32
18028     0/imm32/output-is-write-only
18029     0x11/imm32/alloc-id:fake
18030     _Primitive-and-lit-with-mem/imm32/next
18031 _Primitive-and-lit-with-mem:  # (payload primitive)
18032     0x11/imm32/alloc-id:fake:payload
18033     # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32
18034     0x11/imm32/alloc-id:fake
18035     _string-and-with/imm32/name
18036     0x11/imm32/alloc-id:fake
18037     Int-var-and-literal/imm32/inouts
18038     0/imm32/no-outputs
18039     0/imm32/no-outputs
18040     0x11/imm32/alloc-id:fake
18041     _string_81_subop_and/imm32/subx-name
18042     1/imm32/rm32-is-first-inout
18043     0/imm32/no-r32
18044     2/imm32/imm32-is-second-inout
18045     0/imm32/no-imm8
18046     0/imm32/no-disp32
18047     0/imm32/output-is-write-only
18048     0x11/imm32/alloc-id:fake
18049     _Primitive-or-with-eax/imm32/next
18050 # - or
18051 _Primitive-or-with-eax:  # (payload primitive)
18052     0x11/imm32/alloc-id:fake:payload
18053     # var/eax <- or lit => 0d/or-with-eax lit/imm32
18054     0x11/imm32/alloc-id:fake
18055     _string-or/imm32/name
18056     0x11/imm32/alloc-id:fake
18057     Single-lit-var/imm32/inouts
18058     0x11/imm32/alloc-id:fake
18059     Single-int-var-in-eax/imm32/outputs
18060     0x11/imm32/alloc-id:fake
18061     _string_0d_or_with_eax/imm32/subx-name
18062     0/imm32/no-rm32
18063     0/imm32/no-r32
18064     1/imm32/imm32-is-first-inout
18065     0/imm32/no-imm8
18066     0/imm32/no-disp32
18067     0/imm32/output-is-write-only
18068     0x11/imm32/alloc-id:fake
18069     _Primitive-or-reg-with-reg/imm32/next
18070 _Primitive-or-reg-with-reg:  # (payload primitive)
18071     0x11/imm32/alloc-id:fake:payload
18072     # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32
18073     0x11/imm32/alloc-id:fake
18074     _string-or/imm32/name
18075     0x11/imm32/alloc-id:fake
18076     Single-int-var-in-some-register/imm32/inouts
18077     0x11/imm32/alloc-id:fake
18078     Single-int-var-in-some-register/imm32/outputs
18079     0x11/imm32/alloc-id:fake
18080     _string_09_or_with/imm32/subx-name
18081     3/imm32/rm32-is-first-output
18082     1/imm32/r32-is-first-inout
18083     0/imm32/no-imm32
18084     0/imm32/no-imm8
18085     0/imm32/no-disp32
18086     0/imm32/output-is-write-only
18087     0x11/imm32/alloc-id:fake
18088     _Primitive-or-reg-with-mem/imm32/next
18089 _Primitive-or-reg-with-mem:  # (payload primitive)
18090     0x11/imm32/alloc-id:fake:payload
18091     # or-with var1 var2/reg => 09/or-with var1 var2/r32
18092     0x11/imm32/alloc-id:fake
18093     _string-or-with/imm32/name
18094     0x11/imm32/alloc-id:fake
18095     Two-args-int-stack-int-reg/imm32/inouts
18096     0/imm32/no-outputs
18097     0/imm32/no-outputs
18098     0x11/imm32/alloc-id:fake
18099     _string_09_or_with/imm32/subx-name
18100     1/imm32/rm32-is-first-inout
18101     2/imm32/r32-is-second-inout
18102     0/imm32/no-imm32
18103     0/imm32/no-imm8
18104     0/imm32/no-disp32
18105     0/imm32/output-is-write-only
18106     0x11/imm32/alloc-id:fake
18107     _Primitive-or-mem-with-reg/imm32/next
18108 _Primitive-or-mem-with-reg:  # (payload primitive)
18109     0x11/imm32/alloc-id:fake:payload
18110     # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32
18111     0x11/imm32/alloc-id:fake
18112     _string-or/imm32/name
18113     0x11/imm32/alloc-id:fake
18114     Single-int-var-in-mem/imm32/inouts
18115     0x11/imm32/alloc-id:fake
18116     Single-int-var-in-some-register/imm32/outputs
18117     0x11/imm32/alloc-id:fake
18118     _string_0b_or/imm32/subx-name
18119     1/imm32/rm32-is-first-inout
18120     3/imm32/r32-is-first-output
18121     0/imm32/no-imm32
18122     0/imm32/no-imm8
18123     0/imm32/no-disp32
18124     0/imm32/output-is-write-only
18125     0x11/imm32/alloc-id:fake
18126     _Primitive-or-lit-with-reg/imm32/next
18127 _Primitive-or-lit-with-reg:  # (payload primitive)
18128     0x11/imm32/alloc-id:fake:payload
18129     # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32
18130     0x11/imm32/alloc-id:fake
18131     _string-or/imm32/name
18132     0x11/imm32/alloc-id:fake
18133     Single-lit-var/imm32/inouts
18134     0x11/imm32/alloc-id:fake
18135     Single-int-var-in-some-register/imm32/outputs
18136     0x11/imm32/alloc-id:fake
18137     _string_81_subop_or/imm32/subx-name
18138     3/imm32/rm32-is-first-output
18139     0/imm32/no-r32
18140     1/imm32/imm32-is-first-inout
18141     0/imm32/no-imm8
18142     0/imm32/no-disp32
18143     0/imm32/output-is-write-only
18144     0x11/imm32/alloc-id:fake
18145     _Primitive-or-lit-with-mem/imm32/next
18146 _Primitive-or-lit-with-mem:  # (payload primitive)
18147     0x11/imm32/alloc-id:fake:payload
18148     # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32
18149     0x11/imm32/alloc-id:fake
18150     _string-or-with/imm32/name
18151     0x11/imm32/alloc-id:fake
18152     Int-var-and-literal/imm32/inouts
18153     0/imm32/no-outputs
18154     0/imm32/no-outputs
18155     0x11/imm32/alloc-id:fake
18156     _string_81_subop_or/imm32/subx-name
18157     1/imm32/rm32-is-first-inout
18158     0/imm32/no-r32
18159     2/imm32/imm32-is-second-inout
18160     0/imm32/no-imm8
18161     0/imm32/no-disp32
18162     0/imm32/output-is-write-only
18163     0x11/imm32/alloc-id:fake
18164     _Primitive-xor-with-eax/imm32/next
18165 # - xor
18166 _Primitive-xor-with-eax:  # (payload primitive)
18167     0x11/imm32/alloc-id:fake:payload
18168     # var/eax <- xor lit => 35/xor-with-eax lit/imm32
18169     0x11/imm32/alloc-id:fake
18170     _string-xor/imm32/name
18171     0x11/imm32/alloc-id:fake
18172     Single-lit-var/imm32/inouts
18173     0x11/imm32/alloc-id:fake
18174     Single-int-var-in-eax/imm32/outputs
18175     0x11/imm32/alloc-id:fake
18176     _string_35_xor_with_eax/imm32/subx-name
18177     0/imm32/no-rm32
18178     0/imm32/no-r32
18179     1/imm32/imm32-is-first-inout
18180     0/imm32/no-imm8
18181     0/imm32/no-disp32
18182     0/imm32/output-is-write-only
18183     0x11/imm32/alloc-id:fake
18184     _Primitive-xor-reg-with-reg/imm32/next
18185 _Primitive-xor-reg-with-reg:  # (payload primitive)
18186     0x11/imm32/alloc-id:fake:payload
18187     # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32
18188     0x11/imm32/alloc-id:fake
18189     _string-xor/imm32/name
18190     0x11/imm32/alloc-id:fake
18191     Single-int-var-in-some-register/imm32/inouts
18192     0x11/imm32/alloc-id:fake
18193     Single-int-var-in-some-register/imm32/outputs
18194     0x11/imm32/alloc-id:fake
18195     _string_31_xor_with/imm32/subx-name
18196     3/imm32/rm32-is-first-output
18197     1/imm32/r32-is-first-inout
18198     0/imm32/no-imm32
18199     0/imm32/no-imm8
18200     0/imm32/no-disp32
18201     0/imm32/output-is-write-only
18202     0x11/imm32/alloc-id:fake
18203     _Primitive-xor-reg-with-mem/imm32/next
18204 _Primitive-xor-reg-with-mem:  # (payload primitive)
18205     0x11/imm32/alloc-id:fake:payload
18206     # xor-with var1 var2/reg => 31/xor-with var1 var2/r32
18207     0x11/imm32/alloc-id:fake
18208     _string-xor-with/imm32/name
18209     0x11/imm32/alloc-id:fake
18210     Two-args-int-stack-int-reg/imm32/inouts
18211     0/imm32/no-outputs
18212     0/imm32/no-outputs
18213     0x11/imm32/alloc-id:fake
18214     _string_31_xor_with/imm32/subx-name
18215     1/imm32/rm32-is-first-inout
18216     2/imm32/r32-is-second-inout
18217     0/imm32/no-imm32
18218     0/imm32/no-imm8
18219     0/imm32/no-disp32
18220     0/imm32/output-is-write-only
18221     0x11/imm32/alloc-id:fake
18222     _Primitive-xor-mem-with-reg/imm32/next
18223 _Primitive-xor-mem-with-reg:  # (payload primitive)
18224     0x11/imm32/alloc-id:fake:payload
18225     # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32
18226     0x11/imm32/alloc-id:fake
18227     _string-xor/imm32/name
18228     0x11/imm32/alloc-id:fake
18229     Single-int-var-in-mem/imm32/inouts
18230     0x11/imm32/alloc-id:fake
18231     Single-int-var-in-some-register/imm32/outputs
18232     0x11/imm32/alloc-id:fake
18233     _string_33_xor/imm32/subx-name
18234     1/imm32/rm32-is-first-inout
18235     3/imm32/r32-is-first-output
18236     0/imm32/no-imm32
18237     0/imm32/no-imm8
18238     0/imm32/no-disp32
18239     0/imm32/output-is-write-only
18240     0x11/imm32/alloc-id:fake
18241     _Primitive-xor-lit-with-reg/imm32/next
18242 _Primitive-xor-lit-with-reg:  # (payload primitive)
18243     0x11/imm32/alloc-id:fake:payload
18244     # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32
18245     0x11/imm32/alloc-id:fake
18246     _string-xor/imm32/name
18247     0x11/imm32/alloc-id:fake
18248     Single-lit-var/imm32/inouts
18249     0x11/imm32/alloc-id:fake
18250     Single-int-var-in-some-register/imm32/outputs
18251     0x11/imm32/alloc-id:fake
18252     _string_81_subop_xor/imm32/subx-name
18253     3/imm32/rm32-is-first-output
18254     0/imm32/no-r32
18255     1/imm32/imm32-is-first-inout
18256     0/imm32/no-imm8
18257     0/imm32/no-disp32
18258     0/imm32/output-is-write-only
18259     0x11/imm32/alloc-id:fake
18260     _Primitive-xor-lit-with-mem/imm32/next
18261 _Primitive-xor-lit-with-mem:  # (payload primitive)
18262     0x11/imm32/alloc-id:fake:payload
18263     # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32
18264     0x11/imm32/alloc-id:fake
18265     _string-xor-with/imm32/name
18266     0x11/imm32/alloc-id:fake
18267     Int-var-and-literal/imm32/inouts
18268     0/imm32/no-outputs
18269     0/imm32/no-outputs
18270     0x11/imm32/alloc-id:fake
18271     _string_81_subop_xor/imm32/subx-name
18272     1/imm32/rm32-is-first-inout
18273     0/imm32/no-r32
18274     2/imm32/imm32-is-second-inout
18275     0/imm32/no-imm8
18276     0/imm32/no-disp32
18277     0/imm32/output-is-write-only
18278     0x11/imm32/alloc-id:fake
18279     _Primitive-shift-reg-left-by-lit/imm32/next
18280 _Primitive-shift-reg-left-by-lit:  # (payload primitive)
18281     0x11/imm32/alloc-id:fake:payload
18282     # var1/reg <- shift-left lit => c1/shift 4/subop/left var1/rm32 lit/imm32
18283     0x11/imm32/alloc-id:fake
18284     _string-shift-left/imm32/name
18285     0x11/imm32/alloc-id:fake
18286     Single-lit-var/imm32/inouts
18287     0x11/imm32/alloc-id:fake
18288     Single-int-var-in-some-register/imm32/outputs
18289     0x11/imm32/alloc-id:fake
18290     _string_c1_subop_shift_left/imm32/subx-name
18291     3/imm32/rm32-is-first-output
18292     0/imm32/no-r32
18293     0/imm32/no-imm32
18294     1/imm32/imm8-is-first-inout
18295     0/imm32/no-disp32
18296     0/imm32/output-is-write-only
18297     0x11/imm32/alloc-id:fake
18298     _Primitive-shift-reg-right-by-lit/imm32/next
18299 _Primitive-shift-reg-right-by-lit:  # (payload primitive)
18300     0x11/imm32/alloc-id:fake:payload
18301     # var1/reg <- shift-right lit => c1/shift 5/subop/right var1/rm32 lit/imm32
18302     0x11/imm32/alloc-id:fake
18303     _string-shift-right/imm32/name
18304     0x11/imm32/alloc-id:fake
18305     Single-lit-var/imm32/inouts
18306     0x11/imm32/alloc-id:fake
18307     Single-int-var-in-some-register/imm32/outputs
18308     0x11/imm32/alloc-id:fake
18309     _string_c1_subop_shift_right_padding_zeroes/imm32/subx-name
18310     3/imm32/rm32-is-first-output
18311     0/imm32/no-r32
18312     0/imm32/no-imm32
18313     1/imm32/imm8-is-first-inout
18314     0/imm32/no-disp32
18315     0/imm32/output-is-write-only
18316     0x11/imm32/alloc-id:fake
18317     _Primitive-shift-reg-right-signed-by-lit/imm32/next
18318 _Primitive-shift-reg-right-signed-by-lit:  # (payload primitive)
18319     0x11/imm32/alloc-id:fake:payload
18320     # var1/reg <- shift-right-signed lit => c1/shift 7/subop/right-preserving-sign var1/rm32 lit/imm32
18321     0x11/imm32/alloc-id:fake
18322     _string-shift-right-signed/imm32/name
18323     0x11/imm32/alloc-id:fake
18324     Single-lit-var/imm32/inouts
18325     0x11/imm32/alloc-id:fake
18326     Single-int-var-in-some-register/imm32/outputs
18327     0x11/imm32/alloc-id:fake
18328     _string_c1_subop_shift_right_preserving_sign/imm32/subx-name
18329     3/imm32/rm32-is-first-output
18330     0/imm32/no-r32
18331     0/imm32/no-imm32
18332     1/imm32/imm8-is-first-inout
18333     0/imm32/no-disp32
18334     0/imm32/output-is-write-only
18335     0x11/imm32/alloc-id:fake
18336     _Primitive-shift-mem-left-by-lit/imm32/next
18337 _Primitive-shift-mem-left-by-lit:  # (payload primitive)
18338     0x11/imm32/alloc-id:fake:payload
18339     # shift-left var1, lit => c1/shift 4/subop/left var1/rm32 lit/imm32
18340     0x11/imm32/alloc-id:fake
18341     _string-shift-left/imm32/name
18342     0x11/imm32/alloc-id:fake
18343     Int-var-and-literal/imm32/inouts
18344     0/imm32/no-outputs
18345     0/imm32/no-outputs
18346     0x11/imm32/alloc-id:fake
18347     _string_c1_subop_shift_left/imm32/subx-name
18348     1/imm32/rm32-is-first-inout
18349     0/imm32/no-r32
18350     0/imm32/no-imm32
18351     2/imm32/imm8-is-second-inout
18352     0/imm32/no-disp32
18353     0/imm32/output-is-write-only
18354     0x11/imm32/alloc-id:fake
18355     _Primitive-shift-mem-right-by-lit/imm32/next
18356 _Primitive-shift-mem-right-by-lit:  # (payload primitive)
18357     0x11/imm32/alloc-id:fake:payload
18358     # shift-right var1, lit => c1/shift 5/subop/right var1/rm32 lit/imm32
18359     0x11/imm32/alloc-id:fake
18360     _string-shift-right/imm32/name
18361     0x11/imm32/alloc-id:fake
18362     Int-var-and-literal/imm32/inouts
18363     0/imm32/no-outputs
18364     0/imm32/no-outputs
18365     0x11/imm32/alloc-id:fake
18366     _string_c1_subop_shift_right_padding_zeroes/imm32/subx-name
18367     1/imm32/rm32-is-first-inout
18368     0/imm32/no-r32
18369     0/imm32/no-imm32
18370     2/imm32/imm8-is-second-inout
18371     0/imm32/no-disp32
18372     0/imm32/output-is-write-only
18373     0x11/imm32/alloc-id:fake
18374     _Primitive-shift-mem-right-signed-by-lit/imm32/next
18375 _Primitive-shift-mem-right-signed-by-lit:  # (payload primitive)
18376     0x11/imm32/alloc-id:fake:payload
18377     # shift-right-signed var1, lit => c1/shift 7/subop/right-preserving-sign var1/rm32 lit/imm32
18378     0x11/imm32/alloc-id:fake
18379     _string-shift-right-signed/imm32/name
18380     0x11/imm32/alloc-id:fake
18381     Int-var-and-literal/imm32/inouts
18382     0/imm32/no-outputs
18383     0/imm32/no-outputs
18384     0x11/imm32/alloc-id:fake
18385     _string_c1_subop_shift_right_preserving_sign/imm32/subx-name
18386     1/imm32/rm32-is-first-inout
18387     0/imm32/no-r32
18388     0/imm32/no-imm32
18389     2/imm32/imm8-is-second-inout
18390     0/imm32/no-disp32
18391     0/imm32/output-is-write-only
18392     0x11/imm32/alloc-id:fake
18393     _Primitive-copy-to-eax/imm32/next
18394 # - copy
18395 _Primitive-copy-to-eax:  # (payload primitive)
18396     0x11/imm32/alloc-id:fake:payload
18397     # var/eax <- copy lit => b8/copy-to-eax lit/imm32
18398     0x11/imm32/alloc-id:fake
18399     _string-copy/imm32/name
18400     0x11/imm32/alloc-id:fake
18401     Single-lit-var/imm32/inouts
18402     0x11/imm32/alloc-id:fake
18403     Single-int-var-in-eax/imm32/outputs
18404     0x11/imm32/alloc-id:fake
18405     _string_b8_copy_to_eax/imm32/subx-name
18406     0/imm32/no-rm32
18407     0/imm32/no-r32
18408     1/imm32/imm32-is-first-inout
18409     0/imm32/no-imm8
18410     0/imm32/no-disp32
18411     1/imm32/output-is-write-only
18412     0x11/imm32/alloc-id:fake
18413     _Primitive-copy-to-ecx/imm32/next
18414 _Primitive-copy-to-ecx:  # (payload primitive)
18415     0x11/imm32/alloc-id:fake:payload
18416     # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32
18417     0x11/imm32/alloc-id:fake
18418     _string-copy/imm32/name
18419     0x11/imm32/alloc-id:fake
18420     Single-lit-var/imm32/inouts
18421     0x11/imm32/alloc-id:fake
18422     Single-int-var-in-ecx/imm32/outputs
18423     0x11/imm32/alloc-id:fake
18424     _string_b9_copy_to_ecx/imm32/subx-name
18425     0/imm32/no-rm32
18426     0/imm32/no-r32
18427     1/imm32/imm32-is-first-inout
18428     0/imm32/no-imm8
18429     0/imm32/no-disp32
18430     1/imm32/output-is-write-only
18431     0x11/imm32/alloc-id:fake
18432     _Primitive-copy-to-edx/imm32/next
18433 _Primitive-copy-to-edx:  # (payload primitive)
18434     0x11/imm32/alloc-id:fake:payload
18435     # var/edx <- copy lit => ba/copy-to-edx lit/imm32
18436     0x11/imm32/alloc-id:fake
18437     _string-copy/imm32/name
18438     0x11/imm32/alloc-id:fake
18439     Single-lit-var/imm32/inouts
18440     0x11/imm32/alloc-id:fake
18441     Single-int-var-in-edx/imm32/outputs
18442     0x11/imm32/alloc-id:fake
18443     _string_ba_copy_to_edx/imm32/subx-name
18444     0/imm32/no-rm32
18445     0/imm32/no-r32
18446     1/imm32/imm32-is-first-inout
18447     0/imm32/no-imm8
18448     0/imm32/no-disp32
18449     1/imm32/output-is-write-only
18450     0x11/imm32/alloc-id:fake
18451     _Primitive-copy-to-ebx/imm32/next
18452 _Primitive-copy-to-ebx:  # (payload primitive)
18453     0x11/imm32/alloc-id:fake:payload
18454     # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32
18455     0x11/imm32/alloc-id:fake
18456     _string-copy/imm32/name
18457     0x11/imm32/alloc-id:fake
18458     Single-lit-var/imm32/inouts
18459     0x11/imm32/alloc-id:fake
18460     Single-int-var-in-ebx/imm32/outputs
18461     0x11/imm32/alloc-id:fake
18462     _string_bb_copy_to_ebx/imm32/subx-name
18463     0/imm32/no-rm32
18464     0/imm32/no-r32
18465     1/imm32/imm32-is-first-inout
18466     0/imm32/no-imm8
18467     0/imm32/no-disp32
18468     1/imm32/output-is-write-only
18469     0x11/imm32/alloc-id:fake
18470     _Primitive-copy-to-esi/imm32/next
18471 _Primitive-copy-to-esi:  # (payload primitive)
18472     0x11/imm32/alloc-id:fake:payload
18473     # var/esi <- copy lit => be/copy-to-esi lit/imm32
18474     0x11/imm32/alloc-id:fake
18475     _string-copy/imm32/name
18476     0x11/imm32/alloc-id:fake
18477     Single-lit-var/imm32/inouts
18478     0x11/imm32/alloc-id:fake
18479     Single-int-var-in-esi/imm32/outputs
18480     0x11/imm32/alloc-id:fake
18481     _string_be_copy_to_esi/imm32/subx-name
18482     0/imm32/no-rm32
18483     0/imm32/no-r32
18484     1/imm32/imm32-is-first-inout
18485     0/imm32/no-imm8
18486     0/imm32/no-disp32
18487     1/imm32/output-is-write-only
18488     0x11/imm32/alloc-id:fake
18489     _Primitive-copy-to-edi/imm32/next
18490 _Primitive-copy-to-edi:  # (payload primitive)
18491     0x11/imm32/alloc-id:fake:payload
18492     # var/edi <- copy lit => bf/copy-to-edi lit/imm32
18493     0x11/imm32/alloc-id:fake
18494     _string-copy/imm32/name
18495     0x11/imm32/alloc-id:fake
18496     Single-lit-var/imm32/inouts
18497     0x11/imm32/alloc-id:fake
18498     Single-int-var-in-edi/imm32/outputs
18499     0x11/imm32/alloc-id:fake
18500     _string_bf_copy_to_edi/imm32/subx-name
18501     0/imm32/no-rm32
18502     0/imm32/no-r32
18503     1/imm32/imm32-is-first-inout
18504     0/imm32/no-imm8
18505     0/imm32/no-disp32
18506     1/imm32/output-is-write-only
18507     0x11/imm32/alloc-id:fake
18508     _Primitive-copy-reg-to-reg/imm32/next
18509 _Primitive-copy-reg-to-reg:  # (payload primitive)
18510     0x11/imm32/alloc-id:fake:payload
18511     # var1/reg <- copy var2/reg => 89/<- var1/rm32 var2/r32
18512     0x11/imm32/alloc-id:fake
18513     _string-copy/imm32/name
18514     0x11/imm32/alloc-id:fake
18515     Single-int-var-in-some-register/imm32/inouts
18516     0x11/imm32/alloc-id:fake
18517     Single-int-var-in-some-register/imm32/outputs
18518     0x11/imm32/alloc-id:fake
18519     _string_89_<-/imm32/subx-name
18520     3/imm32/rm32-is-first-output
18521     1/imm32/r32-is-first-inout
18522     0/imm32/no-imm32
18523     0/imm32/no-imm8
18524     0/imm32/no-disp32
18525     1/imm32/output-is-write-only
18526     0x11/imm32/alloc-id:fake
18527     _Primitive-copy-reg-to-mem/imm32/next
18528 _Primitive-copy-reg-to-mem:  # (payload primitive)
18529     0x11/imm32/alloc-id:fake:payload
18530     # copy-to var1 var2/reg => 89/<- var1 var2/r32
18531     0x11/imm32/alloc-id:fake
18532     _string-copy-to/imm32/name
18533     0x11/imm32/alloc-id:fake
18534     Two-args-int-stack-int-reg/imm32/inouts
18535     0/imm32/no-outputs
18536     0/imm32/no-outputs
18537     0x11/imm32/alloc-id:fake
18538     _string_89_<-/imm32/subx-name
18539     1/imm32/rm32-is-first-inout
18540     2/imm32/r32-is-second-inout
18541     0/imm32/no-imm32
18542     0/imm32/no-imm8
18543     0/imm32/no-disp32
18544     1/imm32/output-is-write-only
18545     0x11/imm32/alloc-id:fake
18546     _Primitive-copy-mem-to-reg/imm32/next
18547 _Primitive-copy-mem-to-reg:  # (payload primitive)
18548     0x11/imm32/alloc-id:fake:payload
18549     # var1/reg <- copy var2 => 8b/-> var2/rm32 var1/r32
18550     0x11/imm32/alloc-id:fake
18551     _string-copy/imm32/name
18552     0x11/imm32/alloc-id:fake
18553     Single-int-var-in-mem/imm32/inouts
18554     0x11/imm32/alloc-id:fake
18555     Single-int-var-in-some-register/imm32/outputs
18556     0x11/imm32/alloc-id:fake
18557     _string_8b_->/imm32/subx-name
18558     1/imm32/rm32-is-first-inout
18559     3/imm32/r32-is-first-output
18560     0/imm32/no-imm32
18561     0/imm32/no-imm8
18562     0/imm32/no-disp32
18563     1/imm32/output-is-write-only
18564     0x11/imm32/alloc-id:fake
18565     _Primitive-copy-lit-to-reg/imm32/next
18566 _Primitive-copy-lit-to-reg:  # (payload primitive)
18567     0x11/imm32/alloc-id:fake:payload
18568     # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32
18569     0x11/imm32/alloc-id:fake
18570     _string-copy/imm32/name
18571     0x11/imm32/alloc-id:fake
18572     Single-lit-var/imm32/inouts
18573     0x11/imm32/alloc-id:fake
18574     Single-int-var-in-some-register/imm32/outputs
18575     0x11/imm32/alloc-id:fake
18576     _string_c7_subop_copy/imm32/subx-name
18577     3/imm32/rm32-is-first-output
18578     0/imm32/no-r32
18579     1/imm32/imm32-is-first-inout
18580     0/imm32/no-imm8
18581     0/imm32/no-disp32
18582     1/imm32/output-is-write-only
18583     0x11/imm32/alloc-id:fake
18584     _Primitive-copy-lit-to-mem/imm32/next
18585 _Primitive-copy-lit-to-mem:  # (payload primitive)
18586     0x11/imm32/alloc-id:fake:payload
18587     # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32
18588     0x11/imm32/alloc-id:fake
18589     _string-copy-to/imm32/name
18590     0x11/imm32/alloc-id:fake
18591     Int-var-and-literal/imm32/inouts
18592     0/imm32/no-outputs
18593     0/imm32/no-outputs
18594     0x11/imm32/alloc-id:fake
18595     _string_c7_subop_copy/imm32/subx-name
18596     1/imm32/rm32-is-first-inout
18597     0/imm32/no-r32
18598     2/imm32/imm32-is-second-inout
18599     0/imm32/no-imm8
18600     0/imm32/no-disp32
18601     1/imm32/output-is-write-only
18602     0x11/imm32/alloc-id:fake
18603     _Primitive-copy-byte-from-reg/imm32/next
18604 # - copy byte
18605 _Primitive-copy-byte-from-reg:
18606     0x11/imm32/alloc-id:fake:payload
18607     # var/reg <- copy-byte var2/reg2 => 8a/byte-> %var2 var/r32
18608     0x11/imm32/alloc-id:fake
18609     _string-copy-byte/imm32/name
18610     0x11/imm32/alloc-id:fake
18611     Single-byte-var-in-some-register/imm32/inouts
18612     0x11/imm32/alloc-id:fake
18613     Single-byte-var-in-some-register/imm32/outputs
18614     0x11/imm32/alloc-id:fake
18615     _string_8a_copy_byte/imm32/subx-name
18616     1/imm32/rm32-is-first-inout
18617     3/imm32/r32-is-first-output
18618     0/imm32/no-imm32
18619     0/imm32/no-imm8
18620     0/imm32/no-disp32
18621     1/imm32/output-is-write-only
18622     0x11/imm32/alloc-id:fake
18623     _Primitive-copy-byte-from-mem/imm32/next
18624 _Primitive-copy-byte-from-mem:
18625     0x11/imm32/alloc-id:fake:payload
18626     # var/reg <- copy-byte *var2/reg2 => 8a/byte-> *var2 var/r32
18627     0x11/imm32/alloc-id:fake
18628     _string-copy-byte/imm32/name
18629     0x11/imm32/alloc-id:fake
18630     Single-byte-var-in-mem/imm32/inouts
18631     0x11/imm32/alloc-id:fake
18632     Single-byte-var-in-some-register/imm32/outputs
18633     0x11/imm32/alloc-id:fake
18634     _string_8a_copy_byte/imm32/subx-name
18635     1/imm32/rm32-is-first-inout
18636     3/imm32/r32-is-first-output
18637     0/imm32/no-imm32
18638     0/imm32/no-imm8
18639     0/imm32/no-disp32
18640     1/imm32/output-is-write-only
18641     0x11/imm32/alloc-id:fake
18642     _Primitive-copy-byte-to-mem/imm32/next
18643 _Primitive-copy-byte-to-mem:
18644     0x11/imm32/alloc-id:fake:payload
18645     # copy-byte-to *var1/reg1, var2/reg2 => 88/byte<- *reg1 reg2/r32
18646     0x11/imm32/alloc-id:fake
18647     _string-copy-byte-to/imm32/name
18648     0x11/imm32/alloc-id:fake
18649     Two-args-byte-stack-byte-reg/imm32/inouts
18650     0/imm32/no-outputs
18651     0/imm32/no-outputs
18652     0x11/imm32/alloc-id:fake
18653     _string_88_copy_byte/imm32/subx-name
18654     1/imm32/rm32-is-first-inout
18655     2/imm32/r32-is-second-inout
18656     0/imm32/no-imm32
18657     0/imm32/no-imm8
18658     0/imm32/no-disp32
18659     0/imm32/output-is-write-only
18660     0x11/imm32/alloc-id:fake
18661     _Primitive-address/imm32/next
18662 # - address
18663 _Primitive-address:  # (payload primitive)
18664     0x11/imm32/alloc-id:fake:payload
18665     # var1/reg <- address var2 => 8d/copy-address var2/rm32 var1/r32
18666     0x11/imm32/alloc-id:fake
18667     _string-address/imm32/name
18668     0x11/imm32/alloc-id:fake
18669     Single-int-var-in-mem/imm32/inouts
18670     0x11/imm32/alloc-id:fake
18671     Single-addr-var-in-some-register/imm32/outputs
18672     0x11/imm32/alloc-id:fake
18673     _string_8d_copy_address/imm32/subx-name
18674     1/imm32/rm32-is-first-inout
18675     3/imm32/r32-is-first-output
18676     0/imm32/no-imm32
18677     0/imm32/no-imm8
18678     0/imm32/no-disp32
18679     1/imm32/output-is-write-only
18680     0x11/imm32/alloc-id:fake
18681     _Primitive-compare-reg-with-reg/imm32/next
18682 # - compare
18683 _Primitive-compare-reg-with-reg:  # (payload primitive)
18684     0x11/imm32/alloc-id:fake:payload
18685     # compare var1/reg1 var2/reg2 => 39/compare var1/rm32 var2/r32
18686     0x11/imm32/alloc-id:fake
18687     _string-compare/imm32/name
18688     0x11/imm32/alloc-id:fake
18689     Two-int-args-in-regs/imm32/inouts
18690     0/imm32/no-outputs
18691     0/imm32/no-outputs
18692     0x11/imm32/alloc-id:fake
18693     _string_39_compare->/imm32/subx-name
18694     1/imm32/rm32-is-first-inout
18695     2/imm32/r32-is-second-inout
18696     0/imm32/no-imm32
18697     0/imm32/no-imm8
18698     0/imm32/no-disp32
18699     0/imm32/output-is-write-only
18700     0x11/imm32/alloc-id:fake
18701     _Primitive-compare-mem-with-reg/imm32/next
18702 _Primitive-compare-mem-with-reg:  # (payload primitive)
18703     0x11/imm32/alloc-id:fake:payload
18704     # compare var1 var2/reg => 39/compare var1/rm32 var2/r32
18705     0x11/imm32/alloc-id:fake
18706     _string-compare/imm32/name
18707     0x11/imm32/alloc-id:fake
18708     Two-args-int-stack-int-reg/imm32/inouts
18709     0/imm32/no-outputs
18710     0/imm32/no-outputs
18711     0x11/imm32/alloc-id:fake
18712     _string_39_compare->/imm32/subx-name
18713     1/imm32/rm32-is-first-inout
18714     2/imm32/r32-is-second-inout
18715     0/imm32/no-imm32
18716     0/imm32/no-imm8
18717     0/imm32/no-disp32
18718     0/imm32/output-is-write-only
18719     0x11/imm32/alloc-id:fake
18720     _Primitive-compare-reg-with-mem/imm32/next
18721 _Primitive-compare-reg-with-mem:  # (payload primitive)
18722     0x11/imm32/alloc-id:fake:payload
18723     # compare var1/reg var2 => 3b/compare<- var2/rm32 var1/r32
18724     0x11/imm32/alloc-id:fake
18725     _string-compare/imm32/name
18726     0x11/imm32/alloc-id:fake
18727     Two-args-int-reg-int-stack/imm32/inouts
18728     0/imm32/no-outputs
18729     0/imm32/no-outputs
18730     0x11/imm32/alloc-id:fake
18731     _string_3b_compare<-/imm32/subx-name
18732     2/imm32/rm32-is-second-inout
18733     1/imm32/r32-is-first-inout
18734     0/imm32/no-imm32
18735     0/imm32/no-imm8
18736     0/imm32/no-disp32
18737     0/imm32/output-is-write-only
18738     0x11/imm32/alloc-id:fake
18739     _Primitive-compare-eax-with-literal/imm32/next
18740 _Primitive-compare-eax-with-literal:  # (payload primitive)
18741     0x11/imm32/alloc-id:fake:payload
18742     # compare var1/eax n => 3d/compare-eax-with n/imm32
18743     0x11/imm32/alloc-id:fake
18744     _string-compare/imm32/name
18745     0x11/imm32/alloc-id:fake
18746     Two-args-int-eax-int-literal/imm32/inouts
18747     0/imm32/no-outputs
18748     0/imm32/no-outputs
18749     0x11/imm32/alloc-id:fake
18750     _string_3d_compare_eax_with/imm32/subx-name
18751     0/imm32/no-rm32
18752     0/imm32/no-r32
18753     2/imm32/imm32-is-second-inout
18754     0/imm32/no-imm8
18755     0/imm32/no-disp32
18756     0/imm32/output-is-write-only
18757     0x11/imm32/alloc-id:fake
18758     _Primitive-compare-reg-with-literal/imm32/next
18759 _Primitive-compare-reg-with-literal:  # (payload primitive)
18760     0x11/imm32/alloc-id:fake:payload
18761     # compare var1/reg n => 81 7/subop/compare %reg n/imm32
18762     0x11/imm32/alloc-id:fake
18763     _string-compare/imm32/name
18764     0x11/imm32/alloc-id:fake
18765     Int-var-in-register-and-literal/imm32/inouts
18766     0/imm32/no-outputs
18767     0/imm32/no-outputs
18768     0x11/imm32/alloc-id:fake
18769     _string_81_subop_compare/imm32/subx-name
18770     1/imm32/rm32-is-first-inout
18771     0/imm32/no-r32
18772     2/imm32/imm32-is-second-inout
18773     0/imm32/no-imm8
18774     0/imm32/no-disp32
18775     0/imm32/output-is-write-only
18776     0x11/imm32/alloc-id:fake
18777     _Primitive-compare-mem-with-literal/imm32/next
18778 _Primitive-compare-mem-with-literal:  # (payload primitive)
18779     0x11/imm32/alloc-id:fake:payload
18780     # compare var1 n => 81 7/subop/compare *(ebp+___) n/imm32
18781     0x11/imm32/alloc-id:fake
18782     _string-compare/imm32/name
18783     0x11/imm32/alloc-id:fake
18784     Int-var-and-literal/imm32/inouts
18785     0/imm32/no-outputs
18786     0/imm32/no-outputs
18787     0x11/imm32/alloc-id:fake
18788     _string_81_subop_compare/imm32/subx-name
18789     1/imm32/rm32-is-first-inout
18790     0/imm32/no-r32
18791     2/imm32/imm32-is-second-inout
18792     0/imm32/no-imm8
18793     0/imm32/no-disp32
18794     0/imm32/output-is-write-only
18795     0x11/imm32/alloc-id:fake
18796     _Primitive-multiply-reg-by-reg/imm32/next
18797 # - multiply
18798 _Primitive-multiply-reg-by-reg:  # (payload primitive)
18799     0x11/imm32/alloc-id:fake:payload
18800     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
18801     0x11/imm32/alloc-id:fake
18802     _string-multiply/imm32/name
18803     0x11/imm32/alloc-id:fake
18804     Single-int-var-in-some-register/imm32/inouts
18805     0x11/imm32/alloc-id:fake
18806     Single-int-var-in-some-register/imm32/outputs
18807     0x11/imm32/alloc-id:fake
18808     _string_0f_af_multiply/imm32/subx-name
18809     1/imm32/rm32-is-first-inout
18810     3/imm32/r32-is-first-output
18811     0/imm32/no-imm32
18812     0/imm32/no-imm8
18813     0/imm32/no-disp32
18814     0/imm32/output-is-write-only
18815     0x11/imm32/alloc-id:fake
18816     _Primitive-multiply-reg-by-mem/imm32/next
18817 _Primitive-multiply-reg-by-mem:  # (payload primitive)
18818     0x11/imm32/alloc-id:fake:payload
18819     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
18820     0x11/imm32/alloc-id:fake
18821     _string-multiply/imm32/name
18822     0x11/imm32/alloc-id:fake
18823     Single-int-var-in-mem/imm32/inouts
18824     0x11/imm32/alloc-id:fake
18825     Single-int-var-in-some-register/imm32/outputs
18826     0x11/imm32/alloc-id:fake
18827     _string_0f_af_multiply/imm32/subx-name
18828     1/imm32/rm32-is-first-inout
18829     3/imm32/r32-is-first-output
18830     0/imm32/no-imm32
18831     0/imm32/no-imm8
18832     0/imm32/no-disp32
18833     0/imm32/output-is-write-only
18834     0x11/imm32/alloc-id:fake
18835     _Primitive-break-if-addr</imm32/next
18836 # - branches
18837 _Primitive-break-if-addr<:  # (payload primitive)
18838     0x11/imm32/alloc-id:fake:payload
18839     0x11/imm32/alloc-id:fake
18840     _string-break-if-addr</imm32/name
18841     0/imm32/no-inouts
18842     0/imm32/no-inouts
18843     0/imm32/no-outputs
18844     0/imm32/no-outputs
18845     0x11/imm32/alloc-id:fake
18846     _string_0f_82_jump_break/imm32/subx-name
18847     0/imm32/no-rm32
18848     0/imm32/no-r32
18849     0/imm32/no-imm32
18850     0/imm32/no-imm8
18851     0/imm32/no-disp32
18852     0/imm32/no-output
18853     0x11/imm32/alloc-id:fake
18854     _Primitive-break-if-addr>=/imm32/next
18855 _Primitive-break-if-addr>=:  # (payload primitive)
18856     0x11/imm32/alloc-id:fake:payload
18857     0x11/imm32/alloc-id:fake
18858     _string-break-if-addr>=/imm32/name
18859     0/imm32/no-inouts
18860     0/imm32/no-inouts
18861     0/imm32/no-outputs
18862     0/imm32/no-outputs
18863     0x11/imm32/alloc-id:fake
18864     _string_0f_83_jump_break/imm32/subx-name
18865     0/imm32/no-rm32
18866     0/imm32/no-r32
18867     0/imm32/no-imm32
18868     0/imm32/no-imm8
18869     0/imm32/no-disp32
18870     0/imm32/no-output
18871     0x11/imm32/alloc-id:fake
18872     _Primitive-break-if-=/imm32/next
18873 _Primitive-break-if-=:  # (payload primitive)
18874     0x11/imm32/alloc-id:fake:payload
18875     0x11/imm32/alloc-id:fake
18876     _string-break-if-=/imm32/name
18877     0/imm32/no-inouts
18878     0/imm32/no-inouts
18879     0/imm32/no-outputs
18880     0/imm32/no-outputs
18881     0x11/imm32/alloc-id:fake
18882     _string_0f_84_jump_break/imm32/subx-name
18883     0/imm32/no-rm32
18884     0/imm32/no-r32
18885     0/imm32/no-imm32
18886     0/imm32/no-imm8
18887     0/imm32/no-disp32
18888     0/imm32/no-output
18889     0x11/imm32/alloc-id:fake
18890     _Primitive-break-if-!=/imm32/next
18891 _Primitive-break-if-!=:  # (payload primitive)
18892     0x11/imm32/alloc-id:fake:payload
18893     0x11/imm32/alloc-id:fake
18894     _string-break-if-!=/imm32/name
18895     0/imm32/no-inouts
18896     0/imm32/no-inouts
18897     0/imm32/no-outputs
18898     0/imm32/no-outputs
18899     0x11/imm32/alloc-id:fake
18900     _string_0f_85_jump_break/imm32/subx-name
18901     0/imm32/no-rm32
18902     0/imm32/no-r32
18903     0/imm32/no-imm32
18904     0/imm32/no-imm8
18905     0/imm32/no-disp32
18906     0/imm32/no-output
18907     0x11/imm32/alloc-id:fake
18908     _Primitive-break-if-addr<=/imm32/next
18909 _Primitive-break-if-addr<=:  # (payload primitive)
18910     0x11/imm32/alloc-id:fake:payload
18911     0x11/imm32/alloc-id:fake
18912     _string-break-if-addr<=/imm32/name
18913     0/imm32/no-inouts
18914     0/imm32/no-inouts
18915     0/imm32/no-outputs
18916     0/imm32/no-outputs
18917     0x11/imm32/alloc-id:fake
18918     _string_0f_86_jump_break/imm32/subx-name
18919     0/imm32/no-rm32
18920     0/imm32/no-r32
18921     0/imm32/no-imm32
18922     0/imm32/no-imm8
18923     0/imm32/no-disp32
18924     0/imm32/no-output
18925     0x11/imm32/alloc-id:fake
18926     _Primitive-break-if-addr>/imm32/next
18927 _Primitive-break-if-addr>:  # (payload primitive)
18928     0x11/imm32/alloc-id:fake:payload
18929     0x11/imm32/alloc-id:fake
18930     _string-break-if-addr>/imm32/name
18931     0/imm32/no-inouts
18932     0/imm32/no-inouts
18933     0/imm32/no-outputs
18934     0/imm32/no-outputs
18935     0x11/imm32/alloc-id:fake
18936     _string_0f_87_jump_break/imm32/subx-name
18937     0/imm32/no-rm32
18938     0/imm32/no-r32
18939     0/imm32/no-imm32
18940     0/imm32/no-imm8
18941     0/imm32/no-disp32
18942     0/imm32/no-output
18943     0x11/imm32/alloc-id:fake
18944     _Primitive-break-if-</imm32/next
18945 _Primitive-break-if-<:  # (payload primitive)
18946     0x11/imm32/alloc-id:fake:payload
18947     0x11/imm32/alloc-id:fake
18948     _string-break-if-</imm32/name
18949     0/imm32/no-inouts
18950     0/imm32/no-inouts
18951     0/imm32/no-outputs
18952     0/imm32/no-outputs
18953     0x11/imm32/alloc-id:fake
18954     _string_0f_8c_jump_break/imm32/subx-name
18955     0/imm32/no-rm32
18956     0/imm32/no-r32
18957     0/imm32/no-imm32
18958     0/imm32/no-imm8
18959     0/imm32/no-disp32
18960     0/imm32/no-output
18961     0x11/imm32/alloc-id:fake
18962     _Primitive-break-if->=/imm32/next
18963 _Primitive-break-if->=:  # (payload primitive)
18964     0x11/imm32/alloc-id:fake:payload
18965     0x11/imm32/alloc-id:fake
18966     _string-break-if->=/imm32/name
18967     0/imm32/no-inouts
18968     0/imm32/no-inouts
18969     0/imm32/no-outputs
18970     0/imm32/no-outputs
18971     0x11/imm32/alloc-id:fake
18972     _string_0f_8d_jump_break/imm32/subx-name
18973     0/imm32/no-rm32
18974     0/imm32/no-r32
18975     0/imm32/no-imm32
18976     0/imm32/no-imm8
18977     0/imm32/no-disp32
18978     0/imm32/no-output
18979     0x11/imm32/alloc-id:fake
18980     _Primitive-break-if-<=/imm32/next
18981 _Primitive-break-if-<=:  # (payload primitive)
18982     0x11/imm32/alloc-id:fake:payload
18983     0x11/imm32/alloc-id:fake
18984     _string-break-if-<=/imm32/name
18985     0/imm32/no-inouts
18986     0/imm32/no-inouts
18987     0/imm32/no-outputs
18988     0/imm32/no-outputs
18989     0x11/imm32/alloc-id:fake
18990     _string_0f_8e_jump_break/imm32/subx-name
18991     0/imm32/no-rm32
18992     0/imm32/no-r32
18993     0/imm32/no-imm32
18994     0/imm32/no-imm8
18995     0/imm32/no-disp32
18996     0/imm32/no-output
18997     0x11/imm32/alloc-id:fake
18998     _Primitive-break-if->/imm32/next
18999 _Primitive-break-if->:  # (payload primitive)
19000     0x11/imm32/alloc-id:fake:payload
19001     0x11/imm32/alloc-id:fake
19002     _string-break-if->/imm32/name
19003     0/imm32/no-inouts
19004     0/imm32/no-inouts
19005     0/imm32/no-outputs
19006     0/imm32/no-outputs
19007     0x11/imm32/alloc-id:fake
19008     _string_0f_8f_jump_break/imm32/subx-name
19009     0/imm32/no-rm32
19010     0/imm32/no-r32
19011     0/imm32/no-imm32
19012     0/imm32/no-imm8
19013     0/imm32/no-disp32
19014     0/imm32/no-output
19015     0x11/imm32/alloc-id:fake
19016     _Primitive-break/imm32/next
19017 _Primitive-break:  # (payload primitive)
19018     0x11/imm32/alloc-id:fake:payload
19019     0x11/imm32/alloc-id:fake
19020     _string-break/imm32/name
19021     0/imm32/no-inouts
19022     0/imm32/no-inouts
19023     0/imm32/no-outputs
19024     0/imm32/no-outputs
19025     0x11/imm32/alloc-id:fake
19026     _string_e9_jump_break/imm32/subx-name
19027     0/imm32/no-rm32
19028     0/imm32/no-r32
19029     0/imm32/no-imm32
19030     0/imm32/no-imm8
19031     0/imm32/no-disp32
19032     0/imm32/no-output
19033     0x11/imm32/alloc-id:fake
19034     _Primitive-loop-if-addr</imm32/next
19035 _Primitive-loop-if-addr<:  # (payload primitive)
19036     0x11/imm32/alloc-id:fake:payload
19037     0x11/imm32/alloc-id:fake
19038     _string-loop-if-addr</imm32/name
19039     0/imm32/no-inouts
19040     0/imm32/no-inouts
19041     0/imm32/no-outputs
19042     0/imm32/no-outputs
19043     0x11/imm32/alloc-id:fake
19044     _string_0f_82_jump_loop/imm32/subx-name
19045     0/imm32/no-rm32
19046     0/imm32/no-r32
19047     0/imm32/no-imm32
19048     0/imm32/no-imm8
19049     0/imm32/no-disp32
19050     0/imm32/no-output
19051     0x11/imm32/alloc-id:fake
19052     _Primitive-loop-if-addr>=/imm32/next
19053 _Primitive-loop-if-addr>=:  # (payload primitive)
19054     0x11/imm32/alloc-id:fake:payload
19055     0x11/imm32/alloc-id:fake
19056     _string-loop-if-addr>=/imm32/name
19057     0/imm32/no-inouts
19058     0/imm32/no-inouts
19059     0/imm32/no-outputs
19060     0/imm32/no-outputs
19061     0x11/imm32/alloc-id:fake
19062     _string_0f_83_jump_loop/imm32/subx-name
19063     0/imm32/no-rm32
19064     0/imm32/no-r32
19065     0/imm32/no-imm32
19066     0/imm32/no-imm8
19067     0/imm32/no-disp32
19068     0/imm32/no-output
19069     0x11/imm32/alloc-id:fake
19070     _Primitive-loop-if-=/imm32/next
19071 _Primitive-loop-if-=:  # (payload primitive)
19072     0x11/imm32/alloc-id:fake:payload
19073     0x11/imm32/alloc-id:fake
19074     _string-loop-if-=/imm32/name
19075     0/imm32/no-inouts
19076     0/imm32/no-inouts
19077     0/imm32/no-outputs
19078     0/imm32/no-outputs
19079     0x11/imm32/alloc-id:fake
19080     _string_0f_84_jump_loop/imm32/subx-name
19081     0/imm32/no-rm32
19082     0/imm32/no-r32
19083     0/imm32/no-imm32
19084     0/imm32/no-imm8
19085     0/imm32/no-disp32
19086     0/imm32/no-output
19087     0x11/imm32/alloc-id:fake
19088     _Primitive-loop-if-!=/imm32/next
19089 _Primitive-loop-if-!=:  # (payload primitive)
19090     0x11/imm32/alloc-id:fake:payload
19091     0x11/imm32/alloc-id:fake
19092     _string-loop-if-!=/imm32/name
19093     0/imm32/no-inouts
19094     0/imm32/no-inouts
19095     0/imm32/no-outputs
19096     0/imm32/no-outputs
19097     0x11/imm32/alloc-id:fake
19098     _string_0f_85_jump_loop/imm32/subx-name
19099     0/imm32/no-rm32
19100     0/imm32/no-r32
19101     0/imm32/no-imm32
19102     0/imm32/no-imm8
19103     0/imm32/no-disp32
19104     0/imm32/no-output
19105     0x11/imm32/alloc-id:fake
19106     _Primitive-loop-if-addr<=/imm32/next
19107 _Primitive-loop-if-addr<=:  # (payload primitive)
19108     0x11/imm32/alloc-id:fake:payload
19109     0x11/imm32/alloc-id:fake
19110     _string-loop-if-addr<=/imm32/name
19111     0/imm32/no-inouts
19112     0/imm32/no-inouts
19113     0/imm32/no-outputs
19114     0/imm32/no-outputs
19115     0x11/imm32/alloc-id:fake
19116     _string_0f_86_jump_loop/imm32/subx-name
19117     0/imm32/no-rm32
19118     0/imm32/no-r32
19119     0/imm32/no-imm32
19120     0/imm32/no-imm8
19121     0/imm32/no-disp32
19122     0/imm32/no-output
19123     0x11/imm32/alloc-id:fake
19124     _Primitive-loop-if-addr>/imm32/next
19125 _Primitive-loop-if-addr>:  # (payload primitive)
19126     0x11/imm32/alloc-id:fake:payload
19127     0x11/imm32/alloc-id:fake
19128     _string-loop-if-addr>/imm32/name
19129     0/imm32/no-inouts
19130     0/imm32/no-inouts
19131     0/imm32/no-outputs
19132     0/imm32/no-outputs
19133     0x11/imm32/alloc-id:fake
19134     _string_0f_87_jump_loop/imm32/subx-name
19135     0/imm32/no-rm32
19136     0/imm32/no-r32
19137     0/imm32/no-imm32
19138     0/imm32/no-imm8
19139     0/imm32/no-disp32
19140     0/imm32/no-output
19141     0x11/imm32/alloc-id:fake
19142     _Primitive-loop-if-</imm32/next
19143 _Primitive-loop-if-<:  # (payload primitive)
19144     0x11/imm32/alloc-id:fake:payload
19145     0x11/imm32/alloc-id:fake
19146     _string-loop-if-</imm32/name
19147     0/imm32/no-inouts
19148     0/imm32/no-inouts
19149     0/imm32/no-outputs
19150     0/imm32/no-outputs
19151     0x11/imm32/alloc-id:fake
19152     _string_0f_8c_jump_loop/imm32/subx-name
19153     0/imm32/no-rm32
19154     0/imm32/no-r32
19155     0/imm32/no-imm32
19156     0/imm32/no-imm8
19157     0/imm32/no-disp32
19158     0/imm32/no-output
19159     0x11/imm32/alloc-id:fake
19160     _Primitive-loop-if->=/imm32/next
19161 _Primitive-loop-if->=:  # (payload primitive)
19162     0x11/imm32/alloc-id:fake:payload
19163     0x11/imm32/alloc-id:fake
19164     _string-loop-if->=/imm32/name
19165     0/imm32/no-inouts
19166     0/imm32/no-inouts
19167     0/imm32/no-outputs
19168     0/imm32/no-outputs
19169     0x11/imm32/alloc-id:fake
19170     _string_0f_8d_jump_loop/imm32/subx-name
19171     0/imm32/no-rm32
19172     0/imm32/no-r32
19173     0/imm32/no-imm32
19174     0/imm32/no-imm8
19175     0/imm32/no-disp32
19176     0/imm32/no-output
19177     0x11/imm32/alloc-id:fake
19178     _Primitive-loop-if-<=/imm32/next
19179 _Primitive-loop-if-<=:  # (payload primitive)
19180     0x11/imm32/alloc-id:fake:payload
19181     0x11/imm32/alloc-id:fake
19182     _string-loop-if-<=/imm32/name
19183     0/imm32/no-inouts
19184     0/imm32/no-inouts
19185     0/imm32/no-outputs
19186     0/imm32/no-outputs
19187     0x11/imm32/alloc-id:fake
19188     _string_0f_8e_jump_loop/imm32/subx-name
19189     0/imm32/no-rm32
19190     0/imm32/no-r32
19191     0/imm32/no-imm32
19192     0/imm32/no-imm8
19193     0/imm32/no-disp32
19194     0/imm32/no-output
19195     0x11/imm32/alloc-id:fake
19196     _Primitive-loop-if->/imm32/next
19197 _Primitive-loop-if->:  # (payload primitive)
19198     0x11/imm32/alloc-id:fake:payload
19199     0x11/imm32/alloc-id:fake
19200     _string-loop-if->/imm32/name
19201     0/imm32/no-inouts
19202     0/imm32/no-inouts
19203     0/imm32/no-outputs
19204     0/imm32/no-outputs
19205     0x11/imm32/alloc-id:fake
19206     _string_0f_8f_jump_loop/imm32/subx-name
19207     0/imm32/no-rm32
19208     0/imm32/no-r32
19209     0/imm32/no-imm32
19210     0/imm32/no-imm8
19211     0/imm32/no-disp32
19212     0/imm32/no-output
19213     0x11/imm32/alloc-id:fake
19214     _Primitive-loop/imm32/next  # we probably don't need an unconditional break
19215 _Primitive-loop:  # (payload primitive)
19216     0x11/imm32/alloc-id:fake:payload
19217     0x11/imm32/alloc-id:fake
19218     _string-loop/imm32/name
19219     0/imm32/no-inouts
19220     0/imm32/no-inouts
19221     0/imm32/no-outputs
19222     0/imm32/no-outputs
19223     0x11/imm32/alloc-id:fake
19224     _string_e9_jump_loop/imm32/subx-name
19225     0/imm32/no-rm32
19226     0/imm32/no-r32
19227     0/imm32/no-imm32
19228     0/imm32/no-imm8
19229     0/imm32/no-disp32
19230     0/imm32/no-output
19231     0x11/imm32/alloc-id:fake
19232     _Primitive-break-if-addr<-named/imm32/next
19233 # - branches to named blocks
19234 _Primitive-break-if-addr<-named:  # (payload primitive)
19235     0x11/imm32/alloc-id:fake:payload
19236     0x11/imm32/alloc-id:fake
19237     _string-break-if-addr</imm32/name
19238     0x11/imm32/alloc-id:fake
19239     Single-lit-var/imm32/inouts
19240     0/imm32/no-outputs
19241     0/imm32/no-outputs
19242     0x11/imm32/alloc-id:fake
19243     _string_0f_82_jump_label/imm32/subx-name
19244     0/imm32/no-rm32
19245     0/imm32/no-r32
19246     0/imm32/no-imm32
19247     0/imm32/no-imm8
19248     1/imm32/disp32-is-first-inout
19249     0/imm32/no-output
19250     0x11/imm32/alloc-id:fake
19251     _Primitive-break-if-addr>=-named/imm32/next
19252 _Primitive-break-if-addr>=-named:  # (payload primitive)
19253     0x11/imm32/alloc-id:fake:payload
19254     0x11/imm32/alloc-id:fake
19255     _string-break-if-addr>=/imm32/name
19256     0x11/imm32/alloc-id:fake
19257     Single-lit-var/imm32/inouts
19258     0/imm32/no-outputs
19259     0/imm32/no-outputs
19260     0x11/imm32/alloc-id:fake
19261     _string_0f_83_jump_label/imm32/subx-name
19262     0/imm32/no-rm32
19263     0/imm32/no-r32
19264     0/imm32/no-imm32
19265     0/imm32/no-imm8
19266     1/imm32/disp32-is-first-inout
19267     0/imm32/no-output
19268     0x11/imm32/alloc-id:fake
19269     _Primitive-break-if-=-named/imm32/next
19270 _Primitive-break-if-=-named:  # (payload primitive)
19271     0x11/imm32/alloc-id:fake:payload
19272     0x11/imm32/alloc-id:fake
19273     _string-break-if-=/imm32/name
19274     0x11/imm32/alloc-id:fake
19275     Single-lit-var/imm32/inouts
19276     0/imm32/no-outputs
19277     0/imm32/no-outputs
19278     0x11/imm32/alloc-id:fake
19279     _string_0f_84_jump_label/imm32/subx-name
19280     0/imm32/no-rm32
19281     0/imm32/no-r32
19282     0/imm32/no-imm32
19283     0/imm32/no-imm8
19284     1/imm32/disp32-is-first-inout
19285     0/imm32/no-output
19286     0x11/imm32/alloc-id:fake
19287     _Primitive-break-if-!=-named/imm32/next
19288 _Primitive-break-if-!=-named:  # (payload primitive)
19289     0x11/imm32/alloc-id:fake:payload
19290     0x11/imm32/alloc-id:fake
19291     _string-break-if-!=/imm32/name
19292     0x11/imm32/alloc-id:fake
19293     Single-lit-var/imm32/inouts
19294     0/imm32/no-outputs
19295     0/imm32/no-outputs
19296     0x11/imm32/alloc-id:fake
19297     _string_0f_85_jump_label/imm32/subx-name
19298     0/imm32/no-rm32
19299     0/imm32/no-r32
19300     0/imm32/no-imm32
19301     0/imm32/no-imm8
19302     1/imm32/disp32-is-first-inout
19303     0/imm32/no-output
19304     0x11/imm32/alloc-id:fake
19305     _Primitive-break-if-addr<=-named/imm32/next
19306 _Primitive-break-if-addr<=-named:  # (payload primitive)
19307     0x11/imm32/alloc-id:fake:payload
19308     0x11/imm32/alloc-id:fake
19309     _string-break-if-addr<=/imm32/name
19310     0x11/imm32/alloc-id:fake
19311     Single-lit-var/imm32/inouts
19312     0/imm32/no-outputs
19313     0/imm32/no-outputs
19314     0x11/imm32/alloc-id:fake
19315     _string_0f_86_jump_label/imm32/subx-name
19316     0/imm32/no-rm32
19317     0/imm32/no-r32
19318     0/imm32/no-imm32
19319     0/imm32/no-imm8
19320     1/imm32/disp32-is-first-inout
19321     0/imm32/no-output
19322     0x11/imm32/alloc-id:fake
19323     _Primitive-break-if-addr>-named/imm32/next
19324 _Primitive-break-if-addr>-named:  # (payload primitive)
19325     0x11/imm32/alloc-id:fake:payload
19326     0x11/imm32/alloc-id:fake
19327     _string-break-if-addr>/imm32/name
19328     0x11/imm32/alloc-id:fake
19329     Single-lit-var/imm32/inouts
19330     0/imm32/no-outputs
19331     0/imm32/no-outputs
19332     0x11/imm32/alloc-id:fake
19333     _string_0f_87_jump_label/imm32/subx-name
19334     0/imm32/no-rm32
19335     0/imm32/no-r32
19336     0/imm32/no-imm32
19337     0/imm32/no-imm8
19338     1/imm32/disp32-is-first-inout
19339     0/imm32/no-output
19340     0x11/imm32/alloc-id:fake
19341     _Primitive-break-if-<-named/imm32/next
19342 _Primitive-break-if-<-named:  # (payload primitive)
19343     0x11/imm32/alloc-id:fake:payload
19344     0x11/imm32/alloc-id:fake
19345     _string-break-if-</imm32/name
19346     0x11/imm32/alloc-id:fake
19347     Single-lit-var/imm32/inouts
19348     0/imm32/no-outputs
19349     0/imm32/no-outputs
19350     0x11/imm32/alloc-id:fake
19351     _string_0f_8c_jump_label/imm32/subx-name
19352     0/imm32/no-rm32
19353     0/imm32/no-r32
19354     0/imm32/no-imm32
19355     0/imm32/no-imm8
19356     1/imm32/disp32-is-first-inout
19357     0/imm32/no-output
19358     0x11/imm32/alloc-id:fake
19359     _Primitive-break-if->=-named/imm32/next
19360 _Primitive-break-if->=-named:  # (payload primitive)
19361     0x11/imm32/alloc-id:fake:payload
19362     0x11/imm32/alloc-id:fake
19363     _string-break-if->=/imm32/name
19364     0x11/imm32/alloc-id:fake
19365     Single-lit-var/imm32/inouts
19366     0/imm32/no-outputs
19367     0/imm32/no-outputs
19368     0x11/imm32/alloc-id:fake
19369     _string_0f_8d_jump_label/imm32/subx-name
19370     0/imm32/no-rm32
19371     0/imm32/no-r32
19372     0/imm32/no-imm32
19373     0/imm32/no-imm8
19374     1/imm32/disp32-is-first-inout
19375     0/imm32/no-output
19376     0x11/imm32/alloc-id:fake
19377     _Primitive-break-if-<=-named/imm32/next
19378 _Primitive-break-if-<=-named:  # (payload primitive)
19379     0x11/imm32/alloc-id:fake:payload
19380     0x11/imm32/alloc-id:fake
19381     _string-break-if-<=/imm32/name
19382     0x11/imm32/alloc-id:fake
19383     Single-lit-var/imm32/inouts
19384     0/imm32/no-outputs
19385     0/imm32/no-outputs
19386     0x11/imm32/alloc-id:fake
19387     _string_0f_8e_jump_label/imm32/subx-name
19388     0/imm32/no-rm32
19389     0/imm32/no-r32
19390     0/imm32/no-imm32
19391     0/imm32/no-imm8
19392     1/imm32/disp32-is-first-inout
19393     0/imm32/no-output
19394     0x11/imm32/alloc-id:fake
19395     _Primitive-break-if->-named/imm32/next
19396 _Primitive-break-if->-named:  # (payload primitive)
19397     0x11/imm32/alloc-id:fake:payload
19398     0x11/imm32/alloc-id:fake
19399     _string-break-if->/imm32/name
19400     0x11/imm32/alloc-id:fake
19401     Single-lit-var/imm32/inouts
19402     0/imm32/no-outputs
19403     0/imm32/no-outputs
19404     0x11/imm32/alloc-id:fake
19405     _string_0f_8f_jump_label/imm32/subx-name
19406     0/imm32/no-rm32
19407     0/imm32/no-r32
19408     0/imm32/no-imm32
19409     0/imm32/no-imm8
19410     1/imm32/disp32-is-first-inout
19411     0/imm32/no-output
19412     0x11/imm32/alloc-id:fake
19413     _Primitive-break-named/imm32/next
19414 _Primitive-break-named:  # (payload primitive)
19415     0x11/imm32/alloc-id:fake:payload
19416     0x11/imm32/alloc-id:fake
19417     _string-break/imm32/name
19418     0x11/imm32/alloc-id:fake
19419     Single-lit-var/imm32/inouts
19420     0/imm32/no-outputs
19421     0/imm32/no-outputs
19422     0x11/imm32/alloc-id:fake
19423     _string_e9_jump_label/imm32/subx-name
19424     0/imm32/no-rm32
19425     0/imm32/no-r32
19426     0/imm32/no-imm32
19427     0/imm32/no-imm8
19428     1/imm32/disp32-is-first-inout
19429     0/imm32/no-output
19430     0x11/imm32/alloc-id:fake
19431     _Primitive-loop-if-addr<-named/imm32/next
19432 _Primitive-loop-if-addr<-named:  # (payload primitive)
19433     0x11/imm32/alloc-id:fake:payload
19434     0x11/imm32/alloc-id:fake
19435     _string-loop-if-addr</imm32/name
19436     0x11/imm32/alloc-id:fake
19437     Single-lit-var/imm32/inouts
19438     0/imm32/no-outputs
19439     0/imm32/no-outputs
19440     0x11/imm32/alloc-id:fake
19441     _string_0f_82_jump_label/imm32/subx-name
19442     0/imm32/no-rm32
19443     0/imm32/no-r32
19444     0/imm32/no-imm32
19445     0/imm32/no-imm8
19446     1/imm32/disp32-is-first-inout
19447     0/imm32/no-output
19448     0x11/imm32/alloc-id:fake
19449     _Primitive-loop-if-addr>=-named/imm32/next
19450 _Primitive-loop-if-addr>=-named:  # (payload primitive)
19451     0x11/imm32/alloc-id:fake:payload
19452     0x11/imm32/alloc-id:fake
19453     _string-loop-if-addr>=/imm32/name
19454     0x11/imm32/alloc-id:fake
19455     Single-lit-var/imm32/inouts
19456     0/imm32/no-outputs
19457     0/imm32/no-outputs
19458     0x11/imm32/alloc-id:fake
19459     _string_0f_83_jump_label/imm32/subx-name
19460     0/imm32/no-rm32
19461     0/imm32/no-r32
19462     0/imm32/no-imm32
19463     0/imm32/no-imm8
19464     1/imm32/disp32-is-first-inout
19465     0/imm32/no-output
19466     0x11/imm32/alloc-id:fake
19467     _Primitive-loop-if-=-named/imm32/next
19468 _Primitive-loop-if-=-named:  # (payload primitive)
19469     0x11/imm32/alloc-id:fake:payload
19470     0x11/imm32/alloc-id:fake
19471     _string-loop-if-=/imm32/name
19472     0x11/imm32/alloc-id:fake
19473     Single-lit-var/imm32/inouts
19474     0/imm32/no-outputs
19475     0/imm32/no-outputs
19476     0x11/imm32/alloc-id:fake
19477     _string_0f_84_jump_label/imm32/subx-name
19478     0/imm32/no-rm32
19479     0/imm32/no-r32
19480     0/imm32/no-imm32
19481     0/imm32/no-imm8
19482     1/imm32/disp32-is-first-inout
19483     0/imm32/no-output
19484     0x11/imm32/alloc-id:fake
19485     _Primitive-loop-if-!=-named/imm32/next
19486 _Primitive-loop-if-!=-named:  # (payload primitive)
19487     0x11/imm32/alloc-id:fake:payload
19488     0x11/imm32/alloc-id:fake
19489     _string-loop-if-!=/imm32/name
19490     0x11/imm32/alloc-id:fake
19491     Single-lit-var/imm32/inouts
19492     0/imm32/no-outputs
19493     0/imm32/no-outputs
19494     0x11/imm32/alloc-id:fake
19495     _string_0f_85_jump_label/imm32/subx-name
19496     0/imm32/no-rm32
19497     0/imm32/no-r32
19498     0/imm32/no-imm32
19499     0/imm32/no-imm8
19500     1/imm32/disp32-is-first-inout
19501     0/imm32/no-output
19502     0x11/imm32/alloc-id:fake
19503     _Primitive-loop-if-addr<=-named/imm32/next
19504 _Primitive-loop-if-addr<=-named:  # (payload primitive)
19505     0x11/imm32/alloc-id:fake:payload
19506     0x11/imm32/alloc-id:fake
19507     _string-loop-if-addr<=/imm32/name
19508     0x11/imm32/alloc-id:fake
19509     Single-lit-var/imm32/inouts
19510     0/imm32/no-outputs
19511     0/imm32/no-outputs
19512     0x11/imm32/alloc-id:fake
19513     _string_0f_86_jump_label/imm32/subx-name
19514     0/imm32/no-rm32
19515     0/imm32/no-r32
19516     0/imm32/no-imm32
19517     0/imm32/no-imm8
19518     1/imm32/disp32-is-first-inout
19519     0/imm32/no-output
19520     0x11/imm32/alloc-id:fake
19521     _Primitive-loop-if-addr>-named/imm32/next
19522 _Primitive-loop-if-addr>-named:  # (payload primitive)
19523     0x11/imm32/alloc-id:fake:payload
19524     0x11/imm32/alloc-id:fake
19525     _string-loop-if-addr>/imm32/name
19526     0x11/imm32/alloc-id:fake
19527     Single-lit-var/imm32/inouts
19528     0/imm32/no-outputs
19529     0/imm32/no-outputs
19530     0x11/imm32/alloc-id:fake
19531     _string_0f_87_jump_label/imm32/subx-name
19532     0/imm32/no-rm32
19533     0/imm32/no-r32
19534     0/imm32/no-imm32
19535     0/imm32/no-imm8
19536     1/imm32/disp32-is-first-inout
19537     0/imm32/no-output
19538     0x11/imm32/alloc-id:fake
19539     _Primitive-loop-if-<-named/imm32/next
19540 _Primitive-loop-if-<-named:  # (payload primitive)
19541     0x11/imm32/alloc-id:fake:payload
19542     0x11/imm32/alloc-id:fake
19543     _string-loop-if-</imm32/name
19544     0x11/imm32/alloc-id:fake
19545     Single-lit-var/imm32/inouts
19546     0/imm32/no-outputs
19547     0/imm32/no-outputs
19548     0x11/imm32/alloc-id:fake
19549     _string_0f_8c_jump_label/imm32/subx-name
19550     0/imm32/no-rm32
19551     0/imm32/no-r32
19552     0/imm32/no-imm32
19553     0/imm32/no-imm8
19554     1/imm32/disp32-is-first-inout
19555     0/imm32/no-output
19556     0x11/imm32/alloc-id:fake
19557     _Primitive-loop-if->=-named/imm32/next
19558 _Primitive-loop-if->=-named:  # (payload primitive)
19559     0x11/imm32/alloc-id:fake:payload
19560     0x11/imm32/alloc-id:fake
19561     _string-loop-if->=/imm32/name
19562     0x11/imm32/alloc-id:fake
19563     Single-lit-var/imm32/inouts
19564     0/imm32/no-outputs
19565     0/imm32/no-outputs
19566     0x11/imm32/alloc-id:fake
19567     _string_0f_8d_jump_label/imm32/subx-name
19568     0/imm32/no-rm32
19569     0/imm32/no-r32
19570     0/imm32/no-imm32
19571     0/imm32/no-imm8
19572     1/imm32/disp32-is-first-inout
19573     0/imm32/no-output
19574     0x11/imm32/alloc-id:fake
19575     _Primitive-loop-if-<=-named/imm32/next
19576 _Primitive-loop-if-<=-named:  # (payload primitive)
19577     0x11/imm32/alloc-id:fake:payload
19578     0x11/imm32/alloc-id:fake
19579     _string-loop-if-<=/imm32/name
19580     0x11/imm32/alloc-id:fake
19581     Single-lit-var/imm32/inouts
19582     0/imm32/no-outputs
19583     0/imm32/no-outputs
19584     0x11/imm32/alloc-id:fake
19585     _string_0f_8e_jump_label/imm32/subx-name
19586     0/imm32/no-rm32
19587     0/imm32/no-r32
19588     0/imm32/no-imm32
19589     0/imm32/no-imm8
19590     1/imm32/disp32-is-first-inout
19591     0/imm32/no-output
19592     0x11/imm32/alloc-id:fake
19593     _Primitive-loop-if->-named/imm32/next
19594 _Primitive-loop-if->-named:  # (payload primitive)
19595     0x11/imm32/alloc-id:fake:payload
19596     0x11/imm32/alloc-id:fake
19597     _string-loop-if->/imm32/name
19598     0x11/imm32/alloc-id:fake
19599     Single-lit-var/imm32/inouts
19600     0/imm32/no-outputs
19601     0/imm32/no-outputs
19602     0x11/imm32/alloc-id:fake
19603     _string_0f_8f_jump_label/imm32/subx-name
19604     0/imm32/no-rm32
19605     0/imm32/no-r32
19606     0/imm32/no-imm32
19607     0/imm32/no-imm8
19608     1/imm32/disp32-is-first-inout
19609     0/imm32/no-output
19610     0x11/imm32/alloc-id:fake
19611     _Primitive-loop-named/imm32/next  # we probably don't need an unconditional break
19612 _Primitive-loop-named:  # (payload primitive)
19613     0x11/imm32/alloc-id:fake:payload
19614     0x11/imm32/alloc-id:fake
19615     _string-loop/imm32/name
19616     0x11/imm32/alloc-id:fake
19617     Single-lit-var/imm32/inouts
19618     0/imm32/no-outputs
19619     0/imm32/no-outputs
19620     0x11/imm32/alloc-id:fake
19621     _string_e9_jump_label/imm32/subx-name
19622     0/imm32/no-rm32
19623     0/imm32/no-r32
19624     0/imm32/no-imm32
19625     0/imm32/no-imm8
19626     1/imm32/disp32-is-first-inout
19627     0/imm32/no-output
19628     0/imm32/next
19629     0/imm32/next
19630 
19631 # string literals for Mu instructions
19632 _string-add:  # (payload array byte)
19633     0x11/imm32/alloc-id:fake:payload
19634     # "add"
19635     0x3/imm32/size
19636     0x61/a 0x64/d 0x64/d
19637 _string-address:  # (payload array byte)
19638     0x11/imm32/alloc-id:fake:payload
19639     # "address"
19640     0x7/imm32/size
19641     0x61/a 0x64/d 0x64/d 0x72/r 0x65/e 0x73/s 0x73/s
19642 _string-add-to:  # (payload array byte)
19643     0x11/imm32/alloc-id:fake:payload
19644     # "add-to"
19645     0x6/imm32/size
19646     0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
19647 _string-and:  # (payload array byte)
19648     0x11/imm32/alloc-id:fake:payload
19649     # "and"
19650     0x3/imm32/size
19651     0x61/a 0x6e/n 0x64/d
19652 _string-and-with:  # (payload array byte)
19653     0x11/imm32/alloc-id:fake:payload
19654     # "and-with"
19655     0x8/imm32/size
19656     0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
19657 _string-break:  # (payload array byte)
19658     0x11/imm32/alloc-id:fake:payload
19659     # "break"
19660     0x5/imm32/size
19661     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k
19662 _string-break-if-<:  # (payload array byte)
19663     0x11/imm32/alloc-id:fake:payload
19664     # "break-if-<"
19665     0xa/imm32/size
19666     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
19667 _string-break-if-<=:  # (payload array byte)
19668     0x11/imm32/alloc-id:fake:payload
19669     # "break-if-<="
19670     0xb/imm32/size
19671     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
19672 _string-break-if-=:  # (payload array byte)
19673     0x11/imm32/alloc-id:fake:payload
19674     # "break-if-="
19675     0xa/imm32/size
19676     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
19677 _string-break-if->:  # (payload array byte)
19678     0x11/imm32/alloc-id:fake:payload
19679     # "break-if->"
19680     0xa/imm32/size
19681     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
19682 _string-break-if->=:  # (payload array byte)
19683     0x11/imm32/alloc-id:fake:payload
19684     # "break-if->="
19685     0xb/imm32/size
19686     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
19687 _string-break-if-!=:  # (payload array byte)
19688     0x11/imm32/alloc-id:fake:payload
19689     # "break-if-!="
19690     0xb/imm32/size
19691     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
19692 _string-break-if-addr<:  # (payload array byte)
19693     0x11/imm32/alloc-id:fake:payload
19694     # "break-if-addr<"
19695     0xe/imm32/size
19696     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/<
19697 _string-break-if-addr<=:  # (payload array byte)
19698     0x11/imm32/alloc-id:fake:payload
19699     # "break-if-addr<="
19700     0xf/imm32/size
19701     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/=
19702 _string-break-if-addr>:  # (payload array byte)
19703     0x11/imm32/alloc-id:fake:payload
19704     # "break-if-addr>"
19705     0xe/imm32/size
19706     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/>
19707 _string-break-if-addr>=:  # (payload array byte)
19708     0x11/imm32/alloc-id:fake:payload
19709     # "break-if-addr>="
19710     0xf/imm32/size
19711     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/=
19712 _string-compare:  # (payload array byte)
19713     0x11/imm32/alloc-id:fake:payload
19714     # "compare"
19715     0x7/imm32/size
19716     0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e
19717 _string-copy:  # (payload array byte)
19718     0x11/imm32/alloc-id:fake:payload
19719     # "copy"
19720     0x4/imm32/size
19721     0x63/c 0x6f/o 0x70/p 0x79/y
19722 _string-copy-to:  # (payload array byte)
19723     0x11/imm32/alloc-id:fake:payload
19724     # "copy-to"
19725     0x7/imm32/size
19726     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o
19727 _string-copy-byte:
19728     0x11/imm32/alloc-id:fake:payload
19729     # "copy-byte"
19730     0x9/imm32/size
19731     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e
19732 _string-copy-byte-to:
19733     0x11/imm32/alloc-id:fake:payload
19734     # "copy-byte-to"
19735     0xc/imm32/size
19736     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x74/t 0x6f/o
19737 _string-decrement:  # (payload array byte)
19738     0x11/imm32/alloc-id:fake:payload
19739     # "decrement"
19740     0x9/imm32/size
19741     0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
19742 _string-increment:  # (payload array byte)
19743     0x11/imm32/alloc-id:fake:payload
19744     # "increment"
19745     0x9/imm32/size
19746     0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
19747 _string-loop:  # (payload array byte)
19748     0x11/imm32/alloc-id:fake:payload
19749     # "loop"
19750     0x4/imm32/size
19751     0x6c/l 0x6f/o 0x6f/o 0x70/p
19752 _string-loop-if-<:  # (payload array byte)
19753     0x11/imm32/alloc-id:fake:payload
19754     # "loop-if-<"
19755     0x9/imm32/size
19756     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
19757 _string-loop-if-<=:  # (payload array byte)
19758     0x11/imm32/alloc-id:fake:payload
19759     # "loop-if-<="
19760     0xa/imm32/size
19761     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
19762 _string-loop-if-=:  # (payload array byte)
19763     0x11/imm32/alloc-id:fake:payload
19764     # "loop-if-="
19765     0x9/imm32/size
19766     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
19767 _string-loop-if->:  # (payload array byte)
19768     0x11/imm32/alloc-id:fake:payload
19769     # "loop-if->"
19770     0x9/imm32/size
19771     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
19772 _string-loop-if->=:  # (payload array byte)
19773     0x11/imm32/alloc-id:fake:payload
19774     # "loop-if->="
19775     0xa/imm32/size
19776     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
19777 _string-loop-if-!=:  # (payload array byte)
19778     0x11/imm32/alloc-id:fake:payload
19779     # "loop-if-!="
19780     0xa/imm32/size
19781     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
19782 _string-loop-if-addr<:  # (payload array byte)
19783     0x11/imm32/alloc-id:fake:payload
19784     # "loop-if-addr<"
19785     0xd/imm32/size
19786     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/<
19787 _string-loop-if-addr<=:  # (payload array byte)
19788     0x11/imm32/alloc-id:fake:payload
19789     # "loop-if-addr<="
19790     0xe/imm32/size
19791     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/=
19792 _string-loop-if-addr>:  # (payload array byte)
19793     0x11/imm32/alloc-id:fake:payload
19794     # "loop-if-addr>"
19795     0xd/imm32/size
19796     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/>
19797 _string-loop-if-addr>=:  # (payload array byte)
19798     0x11/imm32/alloc-id:fake:payload
19799     # "loop-if-addr>="
19800     0xe/imm32/size
19801     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/=
19802 _string-multiply:  # (payload array byte)
19803     0x11/imm32/alloc-id:fake:payload
19804     # "multiply"
19805     0x8/imm32/size
19806     0x6d/m 0x75/u 0x6c/l 0x74/t 0x69/i 0x70/p 0x6c/l 0x79/y
19807 _string-or:  # (payload array byte)
19808     0x11/imm32/alloc-id:fake:payload
19809     # "or"
19810     0x2/imm32/size
19811     0x6f/o 0x72/r
19812 _string-or-with:  # (payload array byte)
19813     0x11/imm32/alloc-id:fake:payload
19814     # "or-with"
19815     0x7/imm32/size
19816     0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
19817 _string-subtract:  # (payload array byte)
19818     0x11/imm32/alloc-id:fake:payload
19819     # "subtract"
19820     0x8/imm32/size
19821     0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
19822 _string-subtract-from:  # (payload array byte)
19823     0x11/imm32/alloc-id:fake:payload
19824     # "subtract-from"
19825     0xd/imm32/size
19826     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
19827 _string-xor:  # (payload array byte)
19828     0x11/imm32/alloc-id:fake:payload
19829     # "xor"
19830     0x3/imm32/size
19831     0x78/x 0x6f/o 0x72/r
19832 _string-xor-with:  # (payload array byte)
19833     0x11/imm32/alloc-id:fake:payload
19834     # "xor-with"
19835     0x8/imm32/size
19836     0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
19837 _string-shift-left:  # (payload array byte)
19838     0x11/imm32/alloc-id:fake:payload
19839     # "shift-left"
19840     0xa/imm32/size
19841     0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x2d/dash 0x6c/l 0x65/e 0x66/f 0x74/t
19842 _string-shift-right:  # (payload array byte)
19843     0x11/imm32/alloc-id:fake:payload
19844     # "shift-right"
19845     0xb/imm32/size
19846     0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x2d/dash 0x72/r 0x69/i 0x67/g 0x68/h 0x74/t
19847 _string-shift-right-signed:  # (payload array byte)
19848     0x11/imm32/alloc-id:fake:payload
19849     # "shift-right-signed"
19850     0x12/imm32/size
19851     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
19852 
19853 # string literals for SubX instructions
19854 _string_01_add_to:  # (payload array byte)
19855     0x11/imm32/alloc-id:fake:payload
19856     # "01/add-to"
19857     0x9/imm32/size
19858     0x30/0 0x31/1 0x2f/slash 0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
19859 _string_03_add:  # (payload array byte)
19860     0x11/imm32/alloc-id:fake:payload
19861     # "03/add"
19862     0x6/imm32/size
19863     0x30/0 0x33/3 0x2f/slash 0x61/a 0x64/d 0x64/d
19864 _string_05_add_to_eax:  # (payload array byte)
19865     0x11/imm32/alloc-id:fake:payload
19866     # "05/add-to-eax"
19867     0xd/imm32/size
19868     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
19869 _string_09_or_with:  # (payload array byte)
19870     0x11/imm32/alloc-id:fake:payload
19871     # "09/or-with"
19872     0xa/imm32/size
19873     0x30/0 0x39/9 0x2f/slash 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
19874 _string_0b_or:  # (payload array byte)
19875     0x11/imm32/alloc-id:fake:payload
19876     # "0b/or"
19877     0x5/imm32/size
19878     0x30/0 0x62/b 0x2f/slash 0x6f/o 0x72/r
19879 _string_0d_or_with_eax:  # (payload array byte)
19880     0x11/imm32/alloc-id:fake:payload
19881     # "0d/or-with-eax"
19882     0xe/imm32/size
19883     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
19884 _string_0f_82_jump_label:  # (payload array byte)
19885     0x11/imm32/alloc-id:fake:payload
19886     # "0f 82/jump-if-addr<"
19887     0x13/imm32/size
19888     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/<
19889 _string_0f_82_jump_break:  # (payload array byte)
19890     0x11/imm32/alloc-id:fake:payload
19891     # "0f 82/jump-if-addr< break/disp32"
19892     0x20/imm32/size
19893     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
19894 _string_0f_82_jump_loop:  # (payload array byte)
19895     0x11/imm32/alloc-id:fake:payload
19896     # "0f 82/jump-if-addr< loop/disp32"
19897     0x1f/imm32/size
19898     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
19899 _string_0f_83_jump_label:  # (payload array byte)
19900     0x11/imm32/alloc-id:fake:payload
19901     # "0f 83/jump-if-addr>="
19902     0x14/imm32/size
19903     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/=
19904 _string_0f_83_jump_break:  # (payload array byte)
19905     0x11/imm32/alloc-id:fake:payload
19906     # "0f 83/jump-if-addr>= break/disp32"
19907     0x21/imm32/size
19908     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
19909 _string_0f_83_jump_loop:  # (payload array byte)
19910     0x11/imm32/alloc-id:fake:payload
19911     # "0f 83/jump-if-addr>= loop/disp32"
19912     0x20/imm32/size
19913     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
19914 _string_0f_84_jump_label:  # (payload array byte)
19915     0x11/imm32/alloc-id:fake:payload
19916     # "0f 84/jump-if-="
19917     0xf/imm32/size
19918     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/=
19919 _string_0f_84_jump_break:  # (payload array byte)
19920     0x11/imm32/alloc-id:fake:payload
19921     # "0f 84/jump-if-= break/disp32"
19922     0x1c/imm32/size
19923     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
19924 _string_0f_84_jump_loop:  # (payload array byte)
19925     0x11/imm32/alloc-id:fake:payload
19926     # "0f 84/jump-if-= loop/disp32"
19927     0x1b/imm32/size
19928     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
19929 _string_0f_85_jump_label:  # (payload array byte)
19930     0x11/imm32/alloc-id:fake:payload
19931     # "0f 85/jump-if-!="
19932     0x10/imm32/size
19933     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/=
19934 _string_0f_85_jump_break:  # (payload array byte)
19935     0x11/imm32/alloc-id:fake:payload
19936     # "0f 85/jump-if-!= break/disp32"
19937     0x1d/imm32/size
19938     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
19939 _string_0f_85_jump_loop:  # (payload array byte)
19940     0x11/imm32/alloc-id:fake:payload
19941     # "0f 85/jump-if-!= loop/disp32"
19942     0x1c/imm32/size
19943     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
19944 _string_0f_86_jump_label:  # (payload array byte)
19945     0x11/imm32/alloc-id:fake:payload
19946     # "0f 86/jump-if-addr<="
19947     0x14/imm32/size
19948     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/=
19949 _string_0f_86_jump_break:  # (payload array byte)
19950     0x11/imm32/alloc-id:fake:payload
19951     # "0f 86/jump-if-addr<= break/disp32"
19952     0x21/imm32/size
19953     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
19954 _string_0f_86_jump_loop:  # (payload array byte)
19955     0x11/imm32/alloc-id:fake:payload
19956     # "0f 86/jump-if-addr<= loop/disp32"
19957     0x20/imm32/size
19958     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
19959 _string_0f_87_jump_label:  # (payload array byte)
19960     0x11/imm32/alloc-id:fake:payload
19961     # "0f 87/jump-if-addr>"
19962     0x13/imm32/size
19963     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/>
19964 _string_0f_87_jump_break:  # (payload array byte)
19965     0x11/imm32/alloc-id:fake:payload
19966     # "0f 87/jump-if-addr> break/disp32"
19967     0x20/imm32/size
19968     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
19969 _string_0f_87_jump_loop:  # (payload array byte)
19970     0x11/imm32/alloc-id:fake:payload
19971     # "0f 87/jump-if-addr> loop/disp32"
19972     0x1f/imm32/size
19973     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
19974 _string_0f_8c_jump_label:  # (payload array byte)
19975     0x11/imm32/alloc-id:fake:payload
19976     # "0f 8c/jump-if-<"
19977     0xf/imm32/size
19978     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/<
19979 _string_0f_8c_jump_break:  # (payload array byte)
19980     0x11/imm32/alloc-id:fake:payload
19981     # "0f 8c/jump-if-< break/disp32"
19982     0x1c/imm32/size
19983     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
19984 _string_0f_8c_jump_loop:  # (payload array byte)
19985     0x11/imm32/alloc-id:fake:payload
19986     # "0f 8c/jump-if-< loop/disp32"
19987     0x1b/imm32/size
19988     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
19989 _string_0f_8d_jump_label:  # (payload array byte)
19990     0x11/imm32/alloc-id:fake:payload
19991     # "0f 8d/jump-if->="
19992     0x10/imm32/size
19993     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/=
19994 _string_0f_8d_jump_break:  # (payload array byte)
19995     0x11/imm32/alloc-id:fake:payload
19996     # "0f 8d/jump-if->= break/disp32"
19997     0x1d/imm32/size
19998     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
19999 _string_0f_8d_jump_loop:  # (payload array byte)
20000     0x11/imm32/alloc-id:fake:payload
20001     # "0f 8d/jump-if->= loop/disp32"
20002     0x1c/imm32/size
20003     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
20004 _string_0f_8e_jump_label:  # (payload array byte)
20005     0x11/imm32/alloc-id:fake:payload
20006     # "0f 8e/jump-if-<="
20007     0x10/imm32/size
20008     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/=
20009 _string_0f_8e_jump_break:  # (payload array byte)
20010     0x11/imm32/alloc-id:fake:payload
20011     # "0f 8e/jump-if-<= break/disp32"
20012     0x1d/imm32/size
20013     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
20014 _string_0f_8e_jump_loop:  # (payload array byte)
20015     0x11/imm32/alloc-id:fake:payload
20016     # "0f 8e/jump-if-<= loop/disp32"
20017     0x1c/imm32/size
20018     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
20019 _string_0f_8f_jump_label:  # (payload array byte)
20020     0x11/imm32/alloc-id:fake:payload
20021     # "0f 8f/jump-if->"
20022     0xf/imm32/size
20023     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/>
20024 _string_0f_8f_jump_break:  # (payload array byte)
20025     0x11/imm32/alloc-id:fake:payload
20026     # "0f 8f/jump-if-> break/disp32"
20027     0x1c/imm32/size
20028     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
20029 _string_0f_8f_jump_loop:  # (payload array byte)
20030     0x11/imm32/alloc-id:fake:payload
20031     # "0f 8f/jump-if-> loop/disp32"
20032     0x1b/imm32/size
20033     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
20034 _string_0f_af_multiply:  # (payload array byte)
20035     0x11/imm32/alloc-id:fake:payload
20036     # "0f af/multiply"
20037     0xe/imm32/size
20038     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
20039 _string_21_and_with:  # (payload array byte)
20040     0x11/imm32/alloc-id:fake:payload
20041     # "21/and-with"
20042     0xb/imm32/size
20043     0x32/2 0x31/1 0x2f/slash 0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
20044 _string_23_and:  # (payload array byte)
20045     0x11/imm32/alloc-id:fake:payload
20046     # "23/and"
20047     0x6/imm32/size
20048     0x32/2 0x33/3 0x2f/slash 0x61/a 0x6e/n 0x64/d
20049 _string_25_and_with_eax:  # (payload array byte)
20050     0x11/imm32/alloc-id:fake:payload
20051     # "25/and-with-eax"
20052     0xf/imm32/size
20053     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
20054 _string_29_subtract_from:  # (payload array byte)
20055     0x11/imm32/alloc-id:fake:payload
20056     # "29/subtract-from"
20057     0x10/imm32/size
20058     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
20059 _string_2b_subtract:  # (payload array byte)
20060     0x11/imm32/alloc-id:fake:payload
20061     # "2b/subtract"
20062     0xb/imm32/size
20063     0x32/2 0x62/b 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
20064 _string_2d_subtract_from_eax:  # (payload array byte)
20065     0x11/imm32/alloc-id:fake:payload
20066     # "2d/subtract-from-eax"
20067     0x14/imm32/size
20068     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
20069 _string_31_xor_with:  # (payload array byte)
20070     0x11/imm32/alloc-id:fake:payload
20071     # "31/xor-with"
20072     0xb/imm32/size
20073     0x33/3 0x31/1 0x2f/slash 0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
20074 _string_33_xor:  # (payload array byte)
20075     0x11/imm32/alloc-id:fake:payload
20076     # "33/xor"
20077     0x6/imm32/size
20078     0x33/3 0x33/3 0x2f/slash 0x78/x 0x6f/o 0x72/r
20079 _string_35_xor_with_eax:  # (payload array byte)
20080     0x11/imm32/alloc-id:fake:payload
20081     # "35/xor-with-eax"
20082     0xf/imm32/size
20083     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
20084 _string_39_compare->:  # (payload array byte)
20085     0x11/imm32/alloc-id:fake:payload
20086     # "39/compare->"
20087     0xc/imm32/size
20088     0x33/3 0x39/9 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x2d/dash 0x3e/>
20089 _string_3b_compare<-:  # (payload array byte)
20090     0x11/imm32/alloc-id:fake:payload
20091     # "3b/compare<-"
20092     0xc/imm32/size
20093     0x33/3 0x62/b 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x3c/< 0x2d/dash
20094 _string_3d_compare_eax_with:  # (payload array byte)
20095     0x11/imm32/alloc-id:fake:payload
20096     # "3d/compare-eax-with"
20097     0x13/imm32/size
20098     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
20099 _string_40_increment_eax:  # (payload array byte)
20100     0x11/imm32/alloc-id:fake:payload
20101     # "40/increment-eax"
20102     0x10/imm32/size
20103     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
20104 _string_41_increment_ecx:  # (payload array byte)
20105     0x11/imm32/alloc-id:fake:payload
20106     # "41/increment-ecx"
20107     0x10/imm32/size
20108     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
20109 _string_42_increment_edx:  # (payload array byte)
20110     0x11/imm32/alloc-id:fake:payload
20111     # "42/increment-edx"
20112     0x10/imm32/size
20113     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
20114 _string_43_increment_ebx:  # (payload array byte)
20115     0x11/imm32/alloc-id:fake:payload
20116     # "43/increment-ebx"
20117     0x10/imm32/size
20118     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
20119 _string_46_increment_esi:  # (payload array byte)
20120     0x11/imm32/alloc-id:fake:payload
20121     # "46/increment-esi"
20122     0x10/imm32/size
20123     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
20124 _string_47_increment_edi:  # (payload array byte)
20125     0x11/imm32/alloc-id:fake:payload
20126     # "47/increment-edi"
20127     0x10/imm32/size
20128     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
20129 _string_48_decrement_eax:  # (payload array byte)
20130     0x11/imm32/alloc-id:fake:payload
20131     # "48/decrement-eax"
20132     0x10/imm32/size
20133     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
20134 _string_49_decrement_ecx:  # (payload array byte)
20135     0x11/imm32/alloc-id:fake:payload
20136     # "49/decrement-ecx"
20137     0x10/imm32/size
20138     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
20139 _string_4a_decrement_edx:  # (payload array byte)
20140     0x11/imm32/alloc-id:fake:payload
20141     # "4a/decrement-edx"
20142     0x10/imm32/size
20143     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
20144 _string_4b_decrement_ebx:  # (payload array byte)
20145     0x11/imm32/alloc-id:fake:payload
20146     # "4b/decrement-ebx"
20147     0x10/imm32/size
20148     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
20149 _string_4e_decrement_esi:  # (payload array byte)
20150     0x11/imm32/alloc-id:fake:payload
20151     # "4e/decrement-esi"
20152     0x10/imm32/size
20153     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
20154 _string_4f_decrement_edi:  # (payload array byte)
20155     0x11/imm32/alloc-id:fake:payload
20156     # "4f/decrement-edi"
20157     0x10/imm32/size
20158     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
20159 _string_81_subop_add:  # (payload array byte)
20160     0x11/imm32/alloc-id:fake:payload
20161     # "81 0/subop/add"
20162     0xe/imm32/size
20163     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
20164 _string_81_subop_or:  # (payload array byte)
20165     0x11/imm32/alloc-id:fake:payload
20166     # "81 1/subop/or"
20167     0xd/imm32/size
20168     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
20169 _string_81_subop_and:  # (payload array byte)
20170     0x11/imm32/alloc-id:fake:payload
20171     # "81 4/subop/and"
20172     0xe/imm32/size
20173     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
20174 _string_81_subop_subtract:  # (payload array byte)
20175     0x11/imm32/alloc-id:fake:payload
20176     # "81 5/subop/subtract"
20177     0x13/imm32/size
20178     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
20179 _string_81_subop_xor:  # (payload array byte)
20180     0x11/imm32/alloc-id:fake:payload
20181     # "81 6/subop/xor"
20182     0xe/imm32/size
20183     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
20184 _string_81_subop_compare:  # (payload array byte)
20185     0x11/imm32/alloc-id:fake:payload
20186     # "81 7/subop/compare"
20187     0x12/imm32/size
20188     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
20189 _string_89_<-:  # (payload array byte)
20190     0x11/imm32/alloc-id:fake:payload
20191     # "89/<-"
20192     0x5/imm32/size
20193     0x38/8 0x39/9 0x2f/slash 0x3c/< 0x2d/dash
20194 _string_8b_->:  # (payload array byte)
20195     0x11/imm32/alloc-id:fake:payload
20196     # "8b/->"
20197     0x5/imm32/size
20198     0x38/8 0x62/b 0x2f/slash 0x2d/dash 0x3e/>
20199 _string_8a_copy_byte:
20200     0x11/imm32/alloc-id:fake:payload
20201     # "8a/byte->"
20202     0x9/imm32/size
20203     0x38/8 0x61/a 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x3e/>
20204 _string_88_copy_byte:
20205     0x11/imm32/alloc-id:fake:payload
20206     # "88/byte<-"
20207     0x9/imm32/size
20208     0x38/8 0x38/8 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x3c/< 0x2d/-
20209 _string_8d_copy_address:  # (payload array byte)
20210     0x11/imm32/alloc-id:fake:payload
20211     # "8d/copy-address"
20212     0xf/imm32/size
20213     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
20214 _string_b8_copy_to_eax:  # (payload array byte)
20215     0x11/imm32/alloc-id:fake:payload
20216     # "b8/copy-to-eax"
20217     0xe/imm32/size
20218     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
20219 _string_b9_copy_to_ecx:  # (payload array byte)
20220     0x11/imm32/alloc-id:fake:payload
20221     # "b9/copy-to-ecx"
20222     0xe/imm32/size
20223     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
20224 _string_ba_copy_to_edx:  # (payload array byte)
20225     0x11/imm32/alloc-id:fake:payload
20226     # "ba/copy-to-edx"
20227     0xe/imm32/size
20228     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
20229 _string_bb_copy_to_ebx:  # (payload array byte)
20230     0x11/imm32/alloc-id:fake:payload
20231     # "bb/copy-to-ebx"
20232     0xe/imm32/size
20233     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
20234 _string_be_copy_to_esi:  # (payload array byte)
20235     0x11/imm32/alloc-id:fake:payload
20236     # "be/copy-to-esi"
20237     0xe/imm32/size
20238     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
20239 _string_bf_copy_to_edi:  # (payload array byte)
20240     0x11/imm32/alloc-id:fake:payload
20241     # "bf/copy-to-edi"
20242     0xe/imm32/size
20243     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
20244 _string_c7_subop_copy:  # (payload array byte)
20245     0x11/imm32/alloc-id:fake:payload
20246     # "c7 0/subop/copy"
20247     0xf/imm32/size
20248     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
20249 _string_e9_jump_label:  # (payload array byte)
20250     0x11/imm32/alloc-id:fake:payload
20251     # "e9/jump"
20252     0x7/imm32/size
20253     0x65/e 0x39/9 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p
20254 _string_e9_jump_break:  # (payload array byte)
20255     0x11/imm32/alloc-id:fake:payload
20256     # "e9/jump break/disp32"
20257     0x14/imm32/size
20258     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
20259 _string_e9_jump_loop:  # (payload array byte)
20260     0x11/imm32/alloc-id:fake:payload
20261     # "e9/jump loop/disp32"
20262     0x13/imm32/size
20263     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
20264 _string_ff_subop_increment:  # (payload array byte)
20265     0x11/imm32/alloc-id:fake:payload
20266     # "ff 0/subop/increment"
20267     0x14/imm32/size
20268     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
20269 _string_ff_subop_decrement:  # (payload array byte)
20270     0x11/imm32/alloc-id:fake:payload
20271     # "ff 1/subop/decrement"
20272     0x14/imm32/size
20273     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
20274 _string_c1_subop_shift_left:  # (payload array byte)
20275     0x11/imm32/alloc-id:fake:payload
20276     # "c1/shift 4/subop/left"
20277     0x15/imm32/size
20278     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
20279 _string_c1_subop_shift_right_padding_zeroes:  # (payload array byte)
20280     0x11/imm32/alloc-id:fake:payload
20281     # "c1/shift 5/subop/right-padding-zeroes"
20282     0x25/imm32/size
20283     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
20284 _string_c1_subop_shift_right_preserving_sign:  # (payload array byte)
20285     0x11/imm32/alloc-id:fake:payload
20286     # "c1/shift 7/subop/right-preserving-sign"
20287     0x26/imm32/size
20288     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
20289 
20290 Single-int-var-in-mem:  # (payload list var)
20291     0x11/imm32/alloc-id:fake:payload
20292     0x11/imm32/alloc-id:fake
20293     Int-var-in-mem/imm32
20294     0/imm32/next
20295     0/imm32/next
20296 
20297 Int-var-in-mem:  # (payload var)
20298     0x11/imm32/alloc-id:fake:payload
20299     0/imm32/name
20300     0/imm32/name
20301     0x11/imm32/alloc-id:fake
20302     Type-int/imm32
20303     1/imm32/some-block-depth
20304     1/imm32/some-stack-offset
20305     0/imm32/no-register
20306     0/imm32/no-register
20307 
20308 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
20309 Single-byte-var-in-mem:  # (payload list var)
20310     0x11/imm32/alloc-id:fake:payload
20311     0x11/imm32/alloc-id:fake
20312     Byte-var-in-mem/imm32
20313     0/imm32/next
20314     0/imm32/next
20315 
20316 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
20317 Byte-var-in-mem:  # (payload var)
20318     0x11/imm32/alloc-id:fake:payload
20319     0/imm32/name
20320     0/imm32/name
20321     0x11/imm32/alloc-id:fake
20322     Type-byte/imm32
20323     1/imm32/some-block-depth
20324     1/imm32/some-stack-offset
20325     0/imm32/no-register
20326     0/imm32/no-register
20327 
20328 Two-args-int-stack-int-reg:  # (payload list var)
20329     0x11/imm32/alloc-id:fake:payload
20330     0x11/imm32/alloc-id:fake
20331     Int-var-in-mem/imm32
20332     0x11/imm32/alloc-id:fake
20333     Single-int-var-in-some-register/imm32/next
20334 
20335 Two-int-args-in-regs:  # (payload list var)
20336     0x11/imm32/alloc-id:fake:payload
20337     0x11/imm32/alloc-id:fake
20338     Int-var-in-some-register/imm32
20339     0x11/imm32/alloc-id:fake
20340     Single-int-var-in-some-register/imm32/next
20341 
20342 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
20343 Two-args-byte-stack-byte-reg:  # (payload list var)
20344     0x11/imm32/alloc-id:fake:payload
20345     0x11/imm32/alloc-id:fake
20346     Byte-var-in-mem/imm32
20347     0x11/imm32/alloc-id:fake
20348     Single-byte-var-in-some-register/imm32/next
20349 
20350 Two-args-int-reg-int-stack:  # (payload list var)
20351     0x11/imm32/alloc-id:fake:payload
20352     0x11/imm32/alloc-id:fake
20353     Int-var-in-some-register/imm32
20354     0x11/imm32/alloc-id:fake
20355     Single-int-var-in-mem/imm32/next
20356 
20357 Two-args-int-eax-int-literal:  # (payload list var)
20358     0x11/imm32/alloc-id:fake:payload
20359     0x11/imm32/alloc-id:fake
20360     Int-var-in-eax/imm32
20361     0x11/imm32/alloc-id:fake
20362     Single-lit-var/imm32/next
20363 
20364 Int-var-and-literal:  # (payload list var)
20365     0x11/imm32/alloc-id:fake:payload
20366     0x11/imm32/alloc-id:fake
20367     Int-var-in-mem/imm32
20368     0x11/imm32/alloc-id:fake
20369     Single-lit-var/imm32/next
20370 
20371 Int-var-in-register-and-literal:  # (payload list var)
20372     0x11/imm32/alloc-id:fake:payload
20373     0x11/imm32/alloc-id:fake
20374     Int-var-in-some-register/imm32
20375     0x11/imm32/alloc-id:fake
20376     Single-lit-var/imm32/next
20377 
20378 Single-int-var-in-some-register:  # (payload list var)
20379     0x11/imm32/alloc-id:fake:payload
20380     0x11/imm32/alloc-id:fake
20381     Int-var-in-some-register/imm32
20382     0/imm32/next
20383     0/imm32/next
20384 
20385 Single-addr-var-in-some-register:  # (payload list var)
20386     0x11/imm32/alloc-id:fake:payload
20387     0x11/imm32/alloc-id:fake
20388     Addr-var-in-some-register/imm32
20389     0/imm32/next
20390     0/imm32/next
20391 
20392 Single-byte-var-in-some-register:  # (payload list var)
20393     0x11/imm32/alloc-id:fake:payload
20394     0x11/imm32/alloc-id:fake
20395     Byte-var-in-some-register/imm32
20396     0/imm32/next
20397     0/imm32/next
20398 
20399 Int-var-in-some-register:  # (payload var)
20400     0x11/imm32/alloc-id:fake:payload
20401     0/imm32/name
20402     0/imm32/name
20403     0x11/imm32/alloc-id:fake
20404     Type-int/imm32
20405     1/imm32/some-block-depth
20406     0/imm32/no-stack-offset
20407     0x11/imm32/alloc-id:fake
20408     Any-register/imm32
20409 
20410 Any-register:  # (payload array byte)
20411     0x11/imm32/alloc-id:fake:payload
20412     1/imm32/size
20413     # data
20414     2a/asterisk
20415 
20416 Addr-var-in-some-register:  # (payload var)
20417     0x11/imm32/alloc-id:fake:payload
20418     0/imm32/name
20419     0/imm32/name
20420     0x11/imm32/alloc-id:fake
20421     Type-addr/imm32
20422     1/imm32/some-block-depth
20423     0/imm32/no-stack-offset
20424     0x11/imm32/alloc-id:fake
20425     Any-register/imm32
20426 
20427 Byte-var-in-some-register:  # (payload var)
20428     0x11/imm32/alloc-id:fake:payload
20429     0/imm32/name
20430     0/imm32/name
20431     0x11/imm32/alloc-id:fake
20432     Type-byte/imm32
20433     1/imm32/some-block-depth
20434     0/imm32/no-stack-offset
20435     0x11/imm32/alloc-id:fake
20436     Any-register/imm32
20437 
20438 Single-int-var-in-eax:  # (payload list var)
20439     0x11/imm32/alloc-id:fake:payload
20440     0x11/imm32/alloc-id:fake
20441     Int-var-in-eax/imm32
20442     0/imm32/next
20443     0/imm32/next
20444 
20445 Int-var-in-eax:
20446     0x11/imm32/alloc-id:fake:payload
20447     0/imm32/name
20448     0/imm32/name
20449     0x11/imm32/alloc-id:fake
20450     Type-int/imm32
20451     1/imm32/some-block-depth
20452     0/imm32/no-stack-offset
20453     0x11/imm32/alloc-id:fake
20454     $Register-eax/imm32
20455 
20456 Single-int-var-in-ecx:  # (payload list var)
20457     0x11/imm32/alloc-id:fake:payload
20458     0x11/imm32/alloc-id:fake
20459     Int-var-in-ecx/imm32
20460     0/imm32/next
20461     0/imm32/next
20462 
20463 Int-var-in-ecx:
20464     0x11/imm32/alloc-id:fake:payload
20465     0/imm32/name
20466     0/imm32/name
20467     0x11/imm32/alloc-id:fake
20468     Type-int/imm32
20469     1/imm32/some-block-depth
20470     0/imm32/no-stack-offset
20471     0x11/imm32/alloc-id:fake
20472     $Register-ecx/imm32/register
20473 
20474 Single-int-var-in-edx:  # (payload list var)
20475     0x11/imm32/alloc-id:fake:payload
20476     0x11/imm32/alloc-id:fake
20477     Int-var-in-edx/imm32
20478     0/imm32/next
20479     0/imm32/next
20480 
20481 Int-var-in-edx:  # (payload list var)
20482     0x11/imm32/alloc-id:fake:payload
20483     0/imm32/name
20484     0/imm32/name
20485     0x11/imm32/alloc-id:fake
20486     Type-int/imm32
20487     1/imm32/some-block-depth
20488     0/imm32/no-stack-offset
20489     0x11/imm32/alloc-id:fake
20490     $Register-edx/imm32/register
20491 
20492 Single-int-var-in-ebx:  # (payload list var)
20493     0x11/imm32/alloc-id:fake:payload
20494     0x11/imm32/alloc-id:fake
20495     Int-var-in-ebx/imm32
20496     0/imm32/next
20497     0/imm32/next
20498 
20499 Int-var-in-ebx:  # (payload list var)
20500     0x11/imm32/alloc-id:fake:payload
20501     0/imm32/name
20502     0/imm32/name
20503     0x11/imm32/alloc-id:fake
20504     Type-int/imm32
20505     1/imm32/some-block-depth
20506     0/imm32/no-stack-offset
20507     0x11/imm32/alloc-id:fake
20508     $Register-ebx/imm32/register
20509 
20510 Single-int-var-in-esi:  # (payload list var)
20511     0x11/imm32/alloc-id:fake:payload
20512     0x11/imm32/alloc-id:fake
20513     Int-var-in-esi/imm32
20514     0/imm32/next
20515     0/imm32/next
20516 
20517 Int-var-in-esi:  # (payload list var)
20518     0x11/imm32/alloc-id:fake:payload
20519     0/imm32/name
20520     0/imm32/name
20521     0x11/imm32/alloc-id:fake
20522     Type-int/imm32
20523     1/imm32/some-block-depth
20524     0/imm32/no-stack-offset
20525     0x11/imm32/alloc-id:fake
20526     $Register-esi/imm32/register
20527 
20528 Single-int-var-in-edi:  # (payload list var)
20529     0x11/imm32/alloc-id:fake:payload
20530     0x11/imm32/alloc-id:fake
20531     Int-var-in-edi/imm32
20532     0/imm32/next
20533     0/imm32/next
20534 
20535 Int-var-in-edi:  # (payload list var)
20536     0x11/imm32/alloc-id:fake:payload
20537     0/imm32/name
20538     0/imm32/name
20539     0x11/imm32/alloc-id:fake
20540     Type-int/imm32
20541     1/imm32/some-block-depth
20542     0/imm32/no-stack-offset
20543     0x11/imm32/alloc-id:fake
20544     $Register-edi/imm32/register
20545 
20546 Single-lit-var:  # (payload list var)
20547     0x11/imm32/alloc-id:fake:payload
20548     0x11/imm32/alloc-id:fake
20549     Lit-var/imm32
20550     0/imm32/next
20551     0/imm32/next
20552 
20553 Lit-var:  # (payload var)
20554     0x11/imm32/alloc-id:fake:payload
20555     0/imm32/name
20556     0/imm32/name
20557     0x11/imm32/alloc-id:fake
20558     Type-literal/imm32
20559     1/imm32/some-block-depth
20560     0/imm32/no-stack-offset
20561     0/imm32/no-register
20562     0/imm32/no-register
20563 
20564 Type-int:  # (payload type-tree)
20565     0x11/imm32/alloc-id:fake:payload
20566     1/imm32/is-atom
20567     1/imm32/value:int
20568     0/imm32/left:unused
20569     0/imm32/right:null
20570     0/imm32/right:null
20571 
20572 Type-literal:  # (payload type-tree)
20573     0x11/imm32/alloc-id:fake:payload
20574     1/imm32/is-atom
20575     0/imm32/value:literal
20576     0/imm32/left:unused
20577     0/imm32/right:null
20578     0/imm32/right:null
20579 
20580 Type-addr:  # (payload type-tree)
20581     0x11/imm32/alloc-id:fake:payload
20582     1/imm32/is-atom
20583     2/imm32/value:addr
20584     0/imm32/left:unused
20585     0/imm32/right:null
20586     0/imm32/right:null
20587 
20588 Type-byte:  # (payload type-tree)
20589     0x11/imm32/alloc-id:fake:payload
20590     1/imm32/is-atom
20591     8/imm32/value:byte
20592     0/imm32/left:unused
20593     0/imm32/right:null
20594     0/imm32/right:null
20595 
20596 == code
20597 emit-subx-primitive:  # out: (addr buffered-file), stmt: (addr stmt), primitive: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
20598     # . prologue
20599     55/push-ebp
20600     89/<- %ebp 4/r32/esp
20601     # . save registers
20602     50/push-eax
20603     51/push-ecx
20604     # ecx = primitive
20605     8b/-> *(ebp+0x10) 1/r32/ecx
20606     # emit primitive name
20607     (emit-indent *(ebp+8) *Curr-block-depth)
20608     (lookup *(ecx+0x18) *(ecx+0x1c))  # Primitive-subx-name Primitive-subx-name => eax
20609     (write-buffered *(ebp+8) %eax)
20610     # emit rm32 if necessary
20611     (emit-subx-rm32 *(ebp+8) *(ecx+0x20) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-rm32
20612     # emit r32 if necessary
20613     (emit-subx-r32 *(ebp+8) *(ecx+0x24) *(ebp+0xc))  # Primitive-subx-r32
20614     # emit imm32 if necessary
20615     (emit-subx-imm32 *(ebp+8) *(ecx+0x28) *(ebp+0xc))  # Primitive-subx-imm32
20616     # emit imm8 if necessary
20617     (emit-subx-imm8 *(ebp+8) *(ecx+0x2c) *(ebp+0xc))  # Primitive-subx-imm8
20618     # emit disp32 if necessary
20619     (emit-subx-disp32 *(ebp+8) *(ecx+0x30) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-disp32
20620     (write-buffered *(ebp+8) Newline)
20621 $emit-subx-primitive:end:
20622     # . restore registers
20623     59/pop-to-ecx
20624     58/pop-to-eax
20625     # . epilogue
20626     89/<- %esp 5/r32/ebp
20627     5d/pop-to-ebp
20628     c3/return
20629 
20630 emit-subx-rm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
20631     # . prologue
20632     55/push-ebp
20633     89/<- %ebp 4/r32/esp
20634     # . save registers
20635     50/push-eax
20636     # if (l == 0) return
20637     81 7/subop/compare *(ebp+0xc) 0/imm32
20638     74/jump-if-= $emit-subx-rm32:end/disp8
20639     # var v/eax: (addr stmt-var)
20640     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
20641     (emit-subx-var-as-rm32 *(ebp+8) %eax)
20642 $emit-subx-rm32:end:
20643     # . restore registers
20644     58/pop-to-eax
20645     # . epilogue
20646     89/<- %esp 5/r32/ebp
20647     5d/pop-to-ebp
20648     c3/return
20649 
20650 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)
20651     # . prologue
20652     55/push-ebp
20653     89/<- %ebp 4/r32/esp
20654     # . save registers
20655     51/push-ecx
20656     # eax = l
20657     8b/-> *(ebp+0xc) 0/r32/eax
20658     # ecx = stmt
20659     8b/-> *(ebp+8) 1/r32/ecx
20660     # if (l == 1) return stmt->inouts
20661     {
20662       3d/compare-eax-and 1/imm32
20663       75/jump-if-!= break/disp8
20664 $get-stmt-operand-from-arg-location:1:
20665       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
20666       eb/jump $get-stmt-operand-from-arg-location:end/disp8
20667     }
20668     # if (l == 2) return stmt->inouts->next
20669     {
20670       3d/compare-eax-and 2/imm32
20671       75/jump-if-!= break/disp8
20672 $get-stmt-operand-from-arg-location:2:
20673       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
20674       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
20675       eb/jump $get-stmt-operand-from-arg-location:end/disp8
20676     }
20677     # if (l == 3) return stmt->outputs
20678     {
20679       3d/compare-eax-and 3/imm32
20680       75/jump-if-!= break/disp8
20681 $get-stmt-operand-from-arg-location:3:
20682       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
20683       eb/jump $get-stmt-operand-from-arg-location:end/disp8
20684     }
20685     # abort
20686     e9/jump $get-stmt-operand-from-arg-location:abort/disp32
20687 $get-stmt-operand-from-arg-location:end:
20688     # . restore registers
20689     59/pop-to-ecx
20690     # . epilogue
20691     89/<- %esp 5/r32/ebp
20692     5d/pop-to-ebp
20693     c3/return
20694 
20695 $get-stmt-operand-from-arg-location:abort:
20696     # error("invalid arg-location " eax)
20697     (write-buffered *(ebp+0x10) "invalid arg-location ")
20698     (write-int32-hex-buffered *(ebp+0x10) %eax)
20699     (write-buffered *(ebp+0x10) Newline)
20700     (flush *(ebp+0x10))
20701     (stop *(ebp+0x14) 1)
20702     # never gets here
20703 
20704 emit-subx-r32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
20705     # . prologue
20706     55/push-ebp
20707     89/<- %ebp 4/r32/esp
20708     # . save registers
20709     50/push-eax
20710     51/push-ecx
20711     # if (l == 0) return
20712     81 7/subop/compare *(ebp+0xc) 0/imm32
20713     0f 84/jump-if-= $emit-subx-r32:end/disp32
20714     # var v/eax: (addr stmt-var)
20715     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
20716     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
20717     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
20718     (maybe-get Mu-registers %eax 0xc)  # => eax: (addr register-index)
20719     (write-buffered *(ebp+8) Space)
20720     (write-int32-hex-buffered *(ebp+8) *eax)
20721     (write-buffered *(ebp+8) "/r32")
20722 $emit-subx-r32:end:
20723     # . restore registers
20724     59/pop-to-ecx
20725     58/pop-to-eax
20726     # . epilogue
20727     89/<- %esp 5/r32/ebp
20728     5d/pop-to-ebp
20729     c3/return
20730 
20731 emit-subx-imm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
20732     # . prologue
20733     55/push-ebp
20734     89/<- %ebp 4/r32/esp
20735     # . save registers
20736     50/push-eax
20737     51/push-ecx
20738     # if (l == 0) return
20739     81 7/subop/compare *(ebp+0xc) 0/imm32
20740     0f 84/jump-if-= $emit-subx-imm32:end/disp32
20741     # var v/eax: (handle var)
20742     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
20743     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
20744     (lookup *eax *(eax+4))  # Var-name Var-name => eax
20745     (write-buffered *(ebp+8) Space)
20746     (write-buffered *(ebp+8) %eax)
20747     (write-buffered *(ebp+8) "/imm32")
20748 $emit-subx-imm32:end:
20749     # . restore registers
20750     59/pop-to-ecx
20751     58/pop-to-eax
20752     # . epilogue
20753     89/<- %esp 5/r32/ebp
20754     5d/pop-to-ebp
20755     c3/return
20756 
20757 emit-subx-imm8:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
20758     # . prologue
20759     55/push-ebp
20760     89/<- %ebp 4/r32/esp
20761     # . save registers
20762     50/push-eax
20763     51/push-ecx
20764     # if (l == 0) return
20765     81 7/subop/compare *(ebp+0xc) 0/imm32
20766     0f 84/jump-if-= $emit-subx-imm32:end/disp32
20767     # var v/eax: (handle var)
20768     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
20769     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
20770     (lookup *eax *(eax+4))  # Var-name Var-name => eax
20771     (write-buffered *(ebp+8) Space)
20772     (write-buffered *(ebp+8) %eax)
20773     (write-buffered *(ebp+8) "/imm8")
20774 $emit-subx-imm8:end:
20775     # . restore registers
20776     59/pop-to-ecx
20777     58/pop-to-eax
20778     # . epilogue
20779     89/<- %esp 5/r32/ebp
20780     5d/pop-to-ebp
20781     c3/return
20782 
20783 emit-subx-disp32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
20784     # . prologue
20785     55/push-ebp
20786     89/<- %ebp 4/r32/esp
20787     # . save registers
20788     50/push-eax
20789     51/push-ecx
20790     # if (location == 0) return
20791     81 7/subop/compare *(ebp+0xc) 0/imm32
20792     0f 84/jump-if-= $emit-subx-disp32:end/disp32
20793     # var v/eax: (addr stmt-var)
20794     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
20795     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
20796     (lookup *eax *(eax+4))  # Var-name Var-name => eax
20797     (write-buffered *(ebp+8) Space)
20798     (write-buffered *(ebp+8) %eax)
20799     # hack: if instruction operation starts with "break", emit ":break"
20800     # var name/ecx: (addr array byte) = lookup(stmt->operation)
20801     8b/-> *(ebp+0x10) 0/r32/eax
20802     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
20803     89/<- %ecx 0/r32/eax
20804     {
20805       (string-starts-with? %ecx "break")  # => eax
20806       3d/compare-eax-and 0/imm32/false
20807       74/jump-if-= break/disp8
20808       (write-buffered *(ebp+8) ":break")
20809     }
20810     # hack: if instruction operation starts with "loop", emit ":loop"
20811     {
20812       (string-starts-with? %ecx "loop")  # => eax
20813       3d/compare-eax-and 0/imm32/false
20814       74/jump-if-= break/disp8
20815       (write-buffered *(ebp+8) ":loop")
20816     }
20817     (write-buffered *(ebp+8) "/disp32")
20818 $emit-subx-disp32:end:
20819     # . restore registers
20820     59/pop-to-ecx
20821     58/pop-to-eax
20822     # . epilogue
20823     89/<- %esp 5/r32/ebp
20824     5d/pop-to-ebp
20825     c3/return
20826 
20827 emit-call:  # out: (addr buffered-file), stmt: (addr stmt)
20828     # . prologue
20829     55/push-ebp
20830     89/<- %ebp 4/r32/esp
20831     # . save registers
20832     50/push-eax
20833     51/push-ecx
20834     #
20835     (emit-indent *(ebp+8) *Curr-block-depth)
20836     (write-buffered *(ebp+8) "(")
20837     # ecx = stmt
20838     8b/-> *(ebp+0xc) 1/r32/ecx
20839     # - emit function name
20840     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
20841     (write-buffered *(ebp+8) %eax)
20842     # - emit arguments
20843     # var curr/eax: (addr stmt-var) = lookup(stmt->inouts)
20844     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
20845     {
20846       # if (curr == null) break
20847       3d/compare-eax-and 0/imm32
20848       74/jump-if-= break/disp8
20849       #
20850       (emit-subx-call-operand *(ebp+8) %eax)
20851       # curr = lookup(curr->next)
20852       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
20853       eb/jump loop/disp8
20854     }
20855     #
20856     (write-buffered *(ebp+8) ")\n")
20857 $emit-call:end:
20858     # . restore registers
20859     59/pop-to-ecx
20860     58/pop-to-eax
20861     # . epilogue
20862     89/<- %esp 5/r32/ebp
20863     5d/pop-to-ebp
20864     c3/return
20865 
20866 emit-subx-call-operand:  # out: (addr buffered-file), s: (addr stmt-var)
20867     # shares code with emit-subx-var-as-rm32
20868     # . prologue
20869     55/push-ebp
20870     89/<- %ebp 4/r32/esp
20871     # . save registers
20872     50/push-eax
20873     51/push-ecx
20874     56/push-esi
20875     # ecx = s
20876     8b/-> *(ebp+0xc) 1/r32/ecx
20877     # var operand/esi: (addr var) = lookup(s->value)
20878     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
20879     89/<- %esi 0/r32/eax
20880     # if (operand->register && !s->is-deref?) emit "%__"
20881     {
20882 $emit-subx-call-operand:check-for-register-direct:
20883       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
20884       74/jump-if-= break/disp8
20885       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
20886       75/jump-if-!= break/disp8
20887 $emit-subx-call-operand:register-direct:
20888       (write-buffered *(ebp+8) " %")
20889       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
20890       (write-buffered *(ebp+8) %eax)
20891       e9/jump $emit-subx-call-operand:end/disp32
20892     }
20893     # else if (operand->register && s->is-deref?) emit "*__"
20894     {
20895 $emit-subx-call-operand:check-for-register-indirect:
20896       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
20897       74/jump-if-= break/disp8
20898       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
20899       74/jump-if-= break/disp8
20900 $emit-subx-call-operand:register-indirect:
20901       (emit-subx-call-operand-register-indirect *(ebp+8) %esi)
20902       e9/jump $emit-subx-call-operand:end/disp32
20903     }
20904     # else if (operand->stack-offset) emit "*(ebp+__)"
20905     {
20906       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
20907       74/jump-if-= break/disp8
20908 $emit-subx-call-operand:stack:
20909       (emit-subx-call-operand-stack *(ebp+8) %esi)
20910       e9/jump $emit-subx-call-operand:end/disp32
20911     }
20912     # else if (operand->type == literal) emit "__"
20913     {
20914       (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
20915       81 7/subop/compare *(eax+4) 0/imm32  # Type-tree-left
20916       75/jump-if-!= break/disp8
20917 $emit-subx-call-operand:literal:
20918       (write-buffered *(ebp+8) Space)
20919       (lookup *esi *(esi+4))  # Var-name Var-name => eax
20920       (write-buffered *(ebp+8) %eax)
20921     }
20922 $emit-subx-call-operand:end:
20923     # . restore registers
20924     5e/pop-to-esi
20925     59/pop-to-ecx
20926     58/pop-to-eax
20927     # . epilogue
20928     89/<- %esp 5/r32/ebp
20929     5d/pop-to-ebp
20930     c3/return
20931 
20932 emit-subx-call-operand-register-indirect:  # out: (addr buffered-file), v: (addr var)
20933     # . prologue
20934     55/push-ebp
20935     89/<- %ebp 4/r32/esp
20936     # . save registers
20937     50/push-eax
20938     51/push-ecx
20939     56/push-esi
20940     # esi = v
20941     8b/-> *(ebp+0xc) 6/r32/esi
20942     # var size/ecx: int = size-of-deref(v)
20943     (size-of-deref %esi)  # => eax
20944     89/<- %ecx 0/r32/eax
20945     # var reg-name/esi: (addr array byte) = lookup(v->register)
20946     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
20947     89/<- %esi 0/r32/eax
20948     # TODO: assert size is a multiple of 4
20949     # var i/eax: int = 0
20950     b8/copy-to-eax 0/imm32
20951     {
20952 $emit-subx-call-operand-register-indirect:loop:
20953       # if (i >= size) break
20954       39/compare %eax 1/r32/ecx
20955       7d/jump-if->= break/disp8
20956       # emit " *(" v->register "+" i ")"
20957       (write-buffered *(ebp+8) " *(")
20958       (write-buffered *(ebp+8) %esi)
20959       (write-buffered *(ebp+8) "+")
20960       (write-int32-hex-buffered *(ebp+8) %eax)
20961       (write-buffered *(ebp+8) ")")
20962       # i += 4
20963       05/add-to-eax 4/imm32
20964       #
20965       eb/jump loop/disp8
20966     }
20967 $emit-subx-call-operand-register-indirect:end:
20968     # . restore registers
20969     5e/pop-to-esi
20970     59/pop-to-ecx
20971     58/pop-to-eax
20972     # . epilogue
20973     89/<- %esp 5/r32/ebp
20974     5d/pop-to-ebp
20975     c3/return
20976 
20977 emit-subx-call-operand-stack:  # out: (addr buffered-file), v: (addr var)
20978     # . prologue
20979     55/push-ebp
20980     89/<- %ebp 4/r32/esp
20981     # . save registers
20982     50/push-eax
20983     51/push-ecx
20984     56/push-esi
20985     # esi = v
20986     8b/-> *(ebp+0xc) 6/r32/esi
20987     # var curr/ecx: int = v->offset
20988     8b/-> *(esi+0x14) 1/r32/ecx  # Var-offset
20989     # var max/eax: int = v->offset + size-of(v)
20990     (size-of %esi)  # => eax
20991     # TODO: assert size is a multiple of 4
20992     01/add-to %eax 1/r32/ecx
20993     {
20994 $emit-subx-call-operand-stack:loop:
20995       # if (curr >= max) break
20996       39/compare %ecx 0/r32/eax
20997       7d/jump-if->= break/disp8
20998       # emit " *(ebp+" curr ")"
20999       (write-buffered *(ebp+8) " *(ebp+")
21000       (write-int32-hex-buffered *(ebp+8) %ecx)
21001       (write-buffered *(ebp+8) ")")
21002       # i += 4
21003       81 0/subop/add %ecx 4/imm32
21004       #
21005       eb/jump loop/disp8
21006     }
21007 $emit-subx-call-operand-stack:end:
21008     # . restore registers
21009     5e/pop-to-esi
21010     59/pop-to-ecx
21011     58/pop-to-eax
21012     # . epilogue
21013     89/<- %esp 5/r32/ebp
21014     5d/pop-to-ebp
21015     c3/return
21016 
21017 emit-subx-var-as-rm32:  # out: (addr buffered-file), s: (addr stmt-var)
21018     # . prologue
21019     55/push-ebp
21020     89/<- %ebp 4/r32/esp
21021     # . save registers
21022     50/push-eax
21023     51/push-ecx
21024     56/push-esi
21025     # ecx = s
21026     8b/-> *(ebp+0xc) 1/r32/ecx
21027     # var operand/esi: (addr var) = lookup(s->value)
21028     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
21029     89/<- %esi 0/r32/eax
21030     # if (operand->register && s->is-deref?) emit "*__"
21031     {
21032 $emit-subx-var-as-rm32:check-for-register-indirect:
21033       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
21034       74/jump-if-= break/disp8
21035       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
21036       74/jump-if-= break/disp8
21037 $emit-subx-var-as-rm32:register-indirect:
21038       (write-buffered *(ebp+8) " *")
21039       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
21040       (write-buffered *(ebp+8) %eax)
21041       e9/jump $emit-subx-var-as-rm32:end/disp32
21042     }
21043     # if (operand->register && !s->is-deref?) emit "%__"
21044     {
21045 $emit-subx-var-as-rm32:check-for-register-direct:
21046       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
21047       74/jump-if-= break/disp8
21048       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
21049       75/jump-if-!= break/disp8
21050 $emit-subx-var-as-rm32:register-direct:
21051       (write-buffered *(ebp+8) " %")
21052       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
21053       (write-buffered *(ebp+8) %eax)
21054       e9/jump $emit-subx-var-as-rm32:end/disp32
21055     }
21056     # else if (operand->stack-offset) emit "*(ebp+__)"
21057     {
21058       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
21059       74/jump-if-= break/disp8
21060 $emit-subx-var-as-rm32:stack:
21061       (write-buffered *(ebp+8) Space)
21062       (write-buffered *(ebp+8) "*(ebp+")
21063       (write-int32-hex-buffered *(ebp+8) *(esi+0x14))  # Var-offset
21064       (write-buffered *(ebp+8) ")")
21065     }
21066 $emit-subx-var-as-rm32:end:
21067     # . restore registers
21068     5e/pop-to-esi
21069     59/pop-to-ecx
21070     58/pop-to-eax
21071     # . epilogue
21072     89/<- %esp 5/r32/ebp
21073     5d/pop-to-ebp
21074     c3/return
21075 
21076 find-matching-primitive:  # primitives: (addr primitive), stmt: (addr stmt) -> result/eax: (addr primitive)
21077     # . prologue
21078     55/push-ebp
21079     89/<- %ebp 4/r32/esp
21080     # . save registers
21081     51/push-ecx
21082     # var curr/ecx: (addr primitive) = primitives
21083     8b/-> *(ebp+8) 1/r32/ecx
21084     {
21085 $find-matching-primitive:loop:
21086       # if (curr == null) break
21087       81 7/subop/compare %ecx 0/imm32
21088       74/jump-if-= break/disp8
21089       # if match(curr, stmt) return curr
21090       {
21091         (mu-stmt-matches-primitive? *(ebp+0xc) %ecx)  # => eax
21092         3d/compare-eax-and 0/imm32/false
21093         74/jump-if-= break/disp8
21094         89/<- %eax 1/r32/ecx
21095         eb/jump $find-matching-primitive:end/disp8
21096       }
21097 $find-matching-primitive:next-primitive:
21098       # curr = curr->next
21099       (lookup *(ecx+0x38) *(ecx+0x3c))  # Primitive-next Primitive-next => eax
21100       89/<- %ecx 0/r32/eax
21101       #
21102       e9/jump loop/disp32
21103     }
21104     # return null
21105     b8/copy-to-eax 0/imm32
21106 $find-matching-primitive:end:
21107     # . restore registers
21108     59/pop-to-ecx
21109     # . epilogue
21110     89/<- %esp 5/r32/ebp
21111     5d/pop-to-ebp
21112     c3/return
21113 
21114 mu-stmt-matches-primitive?:  # stmt: (addr stmt), primitive: (addr primitive) -> result/eax: boolean
21115     # A mu stmt matches a primitive if the name matches, all the inout vars
21116     # match, and all the output vars match.
21117     # Vars match if types match and registers match.
21118     # In addition, a stmt output matches a primitive's output if types match
21119     # and the primitive has a wildcard register.
21120     # . prologue
21121     55/push-ebp
21122     89/<- %ebp 4/r32/esp
21123     # . save registers
21124     51/push-ecx
21125     52/push-edx
21126     53/push-ebx
21127     56/push-esi
21128     57/push-edi
21129     # ecx = stmt
21130     8b/-> *(ebp+8) 1/r32/ecx
21131     # edx = primitive
21132     8b/-> *(ebp+0xc) 2/r32/edx
21133     {
21134 $mu-stmt-matches-primitive?:check-name:
21135       # if (primitive->name != stmt->operation) return false
21136       # . var esi: (addr array byte) = lookup(stmt->operation)
21137       (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
21138       89/<- %esi 0/r32/eax
21139       # . var edi: (addr array byte) = lookup(primitive->name)
21140       (lookup *edx *(edx+4))  # Primitive-name Primitive-name => eax
21141       89/<- %edi 0/r32/eax
21142       (string-equal? %esi %edi)  # => eax
21143       3d/compare-eax-and 0/imm32/false
21144       75/jump-if-!= break/disp8
21145       b8/copy-to-eax 0/imm32
21146       e9/jump $mu-stmt-matches-primitive?:end/disp32
21147     }
21148     # var curr/esi: (addr stmt-var) = lookup(stmt->inouts)
21149     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
21150     89/<- %esi 0/r32/eax
21151     # var curr2/edi: (addr list var) = lookup(primitive->inouts)
21152     (lookup *(edx+8) *(edx+0xc))  # Primitive-inouts Primitive-inouts => eax
21153     89/<- %edi 0/r32/eax
21154     {
21155 $mu-stmt-matches-primitive?:inouts-loop:
21156       # if (curr == 0 && curr2 == 0) move on to check outputs
21157       {
21158 $mu-stmt-matches-primitive?:check-both-inouts-null:
21159         81 7/subop/compare %esi 0/imm32
21160         75/jump-if-!= break/disp8
21161 $mu-stmt-matches-primitive?:stmt-inout-null:
21162         81 7/subop/compare %edi 0/imm32
21163         0f 84/jump-if-= $mu-stmt-matches-primitive?:check-outputs/disp32
21164 $mu-stmt-matches-primitive?:stmt-inout-null-and-prim-inout-not-null:
21165         # return false
21166         b8/copy-to-eax 0/imm32/false
21167         e9/jump $mu-stmt-matches-primitive?:end/disp32
21168       }
21169       # if (curr2 == 0) return false
21170       {
21171 $mu-stmt-matches-primitive?:check-prim-inout-null:
21172         81 7/subop/compare %edi 0/imm32
21173         75/jump-if-!= break/disp8
21174 $mu-stmt-matches-primitive?:prim-inout-null:
21175         b8/copy-to-eax 0/imm32/false
21176         e9/jump $mu-stmt-matches-primitive?:end/disp32
21177       }
21178       # if (curr != curr2) return false
21179       {
21180 $mu-stmt-matches-primitive?:check-inouts-match:
21181         (lookup *edi *(edi+4))  # List-value List-value => eax
21182         (operand-matches-primitive? %esi %eax)  # => eax
21183         3d/compare-eax-and 0/imm32/false
21184         75/jump-if-!= break/disp8
21185 $mu-stmt-matches-primitive?:inouts-match:
21186         b8/copy-to-eax 0/imm32/false
21187         e9/jump $mu-stmt-matches-primitive?:end/disp32
21188       }
21189 $mu-stmt-matches-primitive?:next-inout:
21190       # curr = lookup(curr->next)
21191       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
21192       89/<- %esi 0/r32/eax
21193       # curr2 = lookup(curr2->next)
21194       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
21195       89/<- %edi 0/r32/eax
21196       #
21197       e9/jump loop/disp32
21198     }
21199 $mu-stmt-matches-primitive?:check-outputs:
21200     # var curr/esi: (addr stmt-var) = lookup(stmt->outputs)
21201     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
21202     89/<- %esi 0/r32/eax
21203     # var curr2/edi: (addr list var) = lookup(primitive->outputs)
21204     (lookup *(edx+0x10) *(edx+0x14))  # Primitive-outputs Primitive-outputs => eax
21205     89/<- %edi 0/r32/eax
21206     {
21207 $mu-stmt-matches-primitive?:outputs-loop:
21208       # if (curr == 0) return (curr2 == 0)
21209       {
21210 $mu-stmt-matches-primitive?:check-both-outputs-null:
21211         81 7/subop/compare %esi 0/imm32
21212         75/jump-if-!= break/disp8
21213         {
21214 $mu-stmt-matches-primitive?:stmt-output-null:
21215           81 7/subop/compare %edi 0/imm32
21216           75/jump-if-!= break/disp8
21217 $mu-stmt-matches-primitive?:both-outputs-null:
21218           # return true
21219           b8/copy-to-eax 1/imm32
21220           e9/jump $mu-stmt-matches-primitive?:end/disp32
21221         }
21222 $mu-stmt-matches-primitive?:stmt-output-null-and-prim-output-not-null:
21223         # return false
21224         b8/copy-to-eax 0/imm32
21225         e9/jump $mu-stmt-matches-primitive?:end/disp32
21226       }
21227       # if (curr2 == 0) return false
21228       {
21229 $mu-stmt-matches-primitive?:check-prim-output-null:
21230         81 7/subop/compare %edi 0/imm32
21231         75/jump-if-!= break/disp8
21232 $mu-stmt-matches-primitive?:prim-output-is-null:
21233         b8/copy-to-eax 0/imm32
21234         e9/jump $mu-stmt-matches-primitive?:end/disp32
21235       }
21236       # if (curr != curr2) return false
21237       {
21238 $mu-stmt-matches-primitive?:check-outputs-match:
21239         (lookup *edi *(edi+4))  # List-value List-value => eax
21240         (operand-matches-primitive? %esi %eax)  # => eax
21241         3d/compare-eax-and 0/imm32/false
21242         75/jump-if-!= break/disp8
21243 $mu-stmt-matches-primitive?:outputs-match:
21244         b8/copy-to-eax 0/imm32
21245         e9/jump $mu-stmt-matches-primitive?:end/disp32
21246       }
21247 $mu-stmt-matches-primitive?:next-output:
21248       # curr = lookup(curr->next)
21249       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
21250       89/<- %esi 0/r32/eax
21251       # curr2 = lookup(curr2->next)
21252       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
21253       89/<- %edi 0/r32/eax
21254       #
21255       e9/jump loop/disp32
21256     }
21257 $mu-stmt-matches-primitive?:return-true:
21258     b8/copy-to-eax 1/imm32
21259 $mu-stmt-matches-primitive?:end:
21260     # . restore registers
21261     5f/pop-to-edi
21262     5e/pop-to-esi
21263     5b/pop-to-ebx
21264     5a/pop-to-edx
21265     59/pop-to-ecx
21266     # . epilogue
21267     89/<- %esp 5/r32/ebp
21268     5d/pop-to-ebp
21269     c3/return
21270 
21271 operand-matches-primitive?:  # s: (addr stmt-var), prim-var: (addr var) -> result/eax: boolean
21272     # . prologue
21273     55/push-ebp
21274     89/<- %ebp 4/r32/esp
21275     # . save registers
21276     51/push-ecx
21277     52/push-edx
21278     53/push-ebx
21279     56/push-esi
21280     57/push-edi
21281     # ecx = s
21282     8b/-> *(ebp+8) 1/r32/ecx
21283     # var var/esi: (addr var) = lookup(s->value)
21284     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
21285     89/<- %esi 0/r32/eax
21286     # edi = prim-var
21287     8b/-> *(ebp+0xc) 7/r32/edi
21288 $operand-matches-primitive?:check-type:
21289     # if !category-match?(var->type, prim-var->type) return false
21290     # . var vtype/ebx: (addr type-tree) = lookup(var->type)
21291     (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
21292     89/<- %ebx 0/r32/eax
21293     # . var ptype/eax: (addr type-tree) = lookup(prim-var->type)
21294     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
21295     (subx-type-category-match? %ebx %eax)  # => eax
21296     3d/compare-eax-and 0/imm32/false
21297     0f 84/jump-if-= $operand-matches-primitive?:return-false/disp32
21298     {
21299 $operand-matches-primitive?:check-register:
21300       # if prim-var is in memory and var is in register but dereference, match
21301       {
21302         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
21303         0f 85/jump-if-!= break/disp32
21304         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
21305         74/jump-if-= break/disp8
21306         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
21307         74/jump-if-= break/disp8
21308 $operand-matches-primitive?:var-deref-match:
21309         e9/jump $operand-matches-primitive?:return-true/disp32
21310       }
21311       # if prim-var is in register and var is in register but dereference, no match
21312       {
21313         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
21314         0f 84/jump-if-= break/disp32
21315         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
21316         0f 84/jump-if-= break/disp32
21317         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
21318         74/jump-if-= break/disp8
21319 $operand-matches-primitive?:var-deref-no-match:
21320         e9/jump $operand-matches-primitive?:return-false/disp32
21321       }
21322       # return false if var->register doesn't match prim-var->register
21323       {
21324         # if register addresses are equal, it's a match
21325         # var vreg/ebx: (addr array byte) = lookup(var->register)
21326         (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
21327         89/<- %ebx 0/r32/eax
21328         # var preg/ecx: (addr array byte) = lookup(prim-var->register)
21329         (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
21330         89/<- %ecx 0/r32/eax
21331         # if (vreg == preg) break
21332         39/compare %ecx 3/r32/ebx
21333         74/jump-if-= break/disp8
21334 $operand-matches-primitive?:var-register-no-match:
21335         # if either address is 0, return false
21336         81 7/subop/compare %ebx 0/imm32
21337         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
21338         81 7/subop/compare %ecx 0/imm32
21339         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
21340         # if prim-var->register is wildcard, it's a match
21341         (string-equal? %ecx "*")  # Any-register => eax
21342         3d/compare-eax-and 0/imm32/false
21343         75/jump-if-!= break/disp8
21344 $operand-matches-primitive?:wildcard-no-match:
21345         # if string contents aren't equal, return false
21346         (string-equal? %ecx %ebx)  # => eax
21347         3d/compare-eax-and 0/imm32/false
21348         74/jump-if-= $operand-matches-primitive?:return-false/disp8
21349       }
21350     }
21351 $operand-matches-primitive?:return-true:
21352     b8/copy-to-eax 1/imm32/true
21353     eb/jump $operand-matches-primitive?:end/disp8
21354 $operand-matches-primitive?:return-false:
21355     b8/copy-to-eax 0/imm32/false
21356 $operand-matches-primitive?:end:
21357     # . restore registers
21358     5f/pop-to-edi
21359     5e/pop-to-esi
21360     5b/pop-to-ebx
21361     5a/pop-to-edx
21362     59/pop-to-ecx
21363     # . epilogue
21364     89/<- %esp 5/r32/ebp
21365     5d/pop-to-ebp
21366     c3/return
21367 
21368 find-matching-function:  # functions: (addr function), stmt: (addr stmt) -> result/eax: (addr function)
21369     # . prologue
21370     55/push-ebp
21371     89/<- %ebp 4/r32/esp
21372     # . save registers
21373     51/push-ecx
21374     # var curr/ecx: (handle function) = functions
21375     8b/-> *(ebp+8) 1/r32/ecx
21376     {
21377       # if (curr == null) break
21378       81 7/subop/compare %ecx 0/imm32
21379       74/jump-if-= break/disp8
21380 #?       (write-buffered Stderr "iter\n")
21381 #?       (flush Stderr)
21382       # if match(stmt, curr) return curr
21383       {
21384         (mu-stmt-matches-function? *(ebp+0xc) %ecx)  # => eax
21385         3d/compare-eax-and 0/imm32/false
21386         74/jump-if-= break/disp8
21387         89/<- %eax 1/r32/ecx
21388         eb/jump $find-matching-function:end/disp8
21389       }
21390       # curr = curr->next
21391       (lookup *(ecx+0x20) *(ecx+0x24))  # Function-next Function-next => eax
21392       89/<- %ecx 0/r32/eax
21393       #
21394       eb/jump loop/disp8
21395     }
21396     # return null
21397     b8/copy-to-eax 0/imm32
21398 $find-matching-function:end:
21399     # . restore registers
21400     59/pop-to-ecx
21401     # . epilogue
21402     89/<- %esp 5/r32/ebp
21403     5d/pop-to-ebp
21404     c3/return
21405 
21406 # Just compare names; user-defined functions don't support overloading yet.
21407 mu-stmt-matches-function?:  # stmt: (addr stmt1), function: (addr function) -> result/eax: boolean
21408     # . prologue
21409     55/push-ebp
21410     89/<- %ebp 4/r32/esp
21411     # . save registers
21412     51/push-ecx
21413     # return function->name == stmt->operation
21414     # ecx = lookup(stmt->operation)
21415     8b/-> *(ebp+8) 0/r32/eax
21416     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
21417     89/<- %ecx 0/r32/eax
21418     # eax = lookup(function->name)
21419     8b/-> *(ebp+0xc) 0/r32/eax
21420     (lookup *eax *(eax+4))  # Function-name Function-name => eax
21421     (string-equal? %eax %ecx)  # => eax
21422 $mu-stmt-matches-function?:end:
21423     # . restore registers
21424     59/pop-to-ecx
21425     # . epilogue
21426     89/<- %esp 5/r32/ebp
21427     5d/pop-to-ebp
21428     c3/return
21429 
21430 # Type-checking happens elsewhere. This method is for selecting between
21431 # primitives.
21432 subx-type-category-match?:  # a: (addr type-tree), b: (addr type-tree) -> result/eax: boolean
21433     # . prologue
21434     55/push-ebp
21435     89/<- %ebp 4/r32/esp
21436     # . save registers
21437     51/push-ecx
21438     # var alit/ecx: boolean = is-literal-type?(a)
21439     (is-simple-mu-type? *(ebp+8) 0)  # => eax
21440     89/<- %ecx 0/r32/eax
21441     # var blit/eax: boolean = is-literal-type?(b)
21442     (is-simple-mu-type? *(ebp+0xc) 0)  # => eax
21443     # return alit == blit
21444     39/compare %eax 1/r32/ecx
21445     0f 94/set-byte-if-= %al
21446     81 4/subop/and %eax 0xff/imm32
21447 $subx-type-category-match?:end:
21448     # . restore registers
21449     59/pop-to-ecx
21450     # . epilogue
21451     89/<- %esp 5/r32/ebp
21452     5d/pop-to-ebp
21453     c3/return
21454 
21455 is-simple-mu-type?:  # a: (addr type-tree), n: type-id -> result/eax: boolean
21456     # . prologue
21457     55/push-ebp
21458     89/<- %ebp 4/r32/esp
21459     # . save registers
21460     51/push-ecx
21461     # ecx = n
21462     8b/-> *(ebp+0xc) 1/r32/ecx
21463     # return (a->value == n)
21464     8b/-> *(ebp+8) 0/r32/eax
21465     39/compare *(eax+4) 1/r32/ecx  # Type-tree-value
21466     0f 94/set-byte-if-= %al
21467     81 4/subop/and %eax 0xff/imm32
21468 $is-simple-mu-type?:end:
21469     # . restore registers
21470     59/pop-to-ecx
21471     # . epilogue
21472     89/<- %esp 5/r32/ebp
21473     5d/pop-to-ebp
21474     c3/return
21475 
21476 is-mu-addr-type?:  # a: (addr type-tree) -> result/eax: boolean
21477     # . prologue
21478     55/push-ebp
21479     89/<- %ebp 4/r32/esp
21480     # eax = a
21481     8b/-> *(ebp+8) 0/r32/eax
21482     # if (!a->is-atom?) a = a->left
21483     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
21484     {
21485       75/jump-if-!= break/disp8
21486       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
21487     }
21488     # return (a->value == addr)
21489     81 7/subop/compare *(eax+4) 2/imm32/addr  # Type-tree-value
21490     0f 94/set-byte-if-= %al
21491     81 4/subop/and %eax 0xff/imm32
21492 $is-mu-addr-type?:end:
21493     # . epilogue
21494     89/<- %esp 5/r32/ebp
21495     5d/pop-to-ebp
21496     c3/return
21497 
21498 is-mu-array-type?:  # a: (addr type-tree) -> result/eax: boolean
21499     # . prologue
21500     55/push-ebp
21501     89/<- %ebp 4/r32/esp
21502     # eax = a
21503     8b/-> *(ebp+8) 0/r32/eax
21504     # if (!a->is-atom?) a = a->left
21505     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
21506     {
21507       75/jump-if-!= break/disp8
21508       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
21509     }
21510     # return (a->value == array)
21511     81 7/subop/compare *(eax+4) 3/imm32/array  # Type-tree-value
21512     0f 94/set-byte-if-= %al
21513     81 4/subop/and %eax 0xff/imm32
21514 $is-mu-array-type?:end:
21515     # . epilogue
21516     89/<- %esp 5/r32/ebp
21517     5d/pop-to-ebp
21518     c3/return
21519 
21520 is-mu-stream-type?:  # a: (addr type-tree) -> result/eax: boolean
21521     # . prologue
21522     55/push-ebp
21523     89/<- %ebp 4/r32/esp
21524     # eax = a
21525     8b/-> *(ebp+8) 0/r32/eax
21526     # if (!a->is-atom?) a = a->left
21527     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
21528     {
21529       75/jump-if-!= break/disp8
21530       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
21531     }
21532     # return (a->value == stream)
21533     81 7/subop/compare *(eax+4) 0xb/imm32/stream  # Type-tree-value
21534     0f 94/set-byte-if-= %al
21535     81 4/subop/and %eax 0xff/imm32
21536 $is-mu-stream-type?:end:
21537     # . epilogue
21538     89/<- %esp 5/r32/ebp
21539     5d/pop-to-ebp
21540     c3/return
21541 
21542 test-emit-subx-stmt-primitive:
21543     # Primitive operation on a variable on the stack.
21544     #   increment foo
21545     # =>
21546     #   ff 0/subop/increment *(ebp-8)
21547     #
21548     # There's a variable on the var stack as follows:
21549     #   name: 'foo'
21550     #   type: int
21551     #   stack-offset: -8
21552     #
21553     # There's a primitive with this info:
21554     #   name: 'increment'
21555     #   inouts: int/mem
21556     #   value: 'ff 0/subop/increment'
21557     #
21558     # . prologue
21559     55/push-ebp
21560     89/<- %ebp 4/r32/esp
21561     # setup
21562     (clear-stream _test-output-stream)
21563     (clear-stream $_test-output-buffered-file->buffer)
21564     # simulate allocated payloads starting with an initial fake alloc-id (0x11)
21565 $test-emit-subx-stmt-primitive:initialize-type:
21566     # var type/ecx: (payload type-tree) = int
21567     68/push 0/imm32/right:null
21568     68/push 0/imm32/right:null
21569     68/push 0/imm32/left:unused
21570     68/push 1/imm32/value:int
21571     68/push 1/imm32/is-atom?:true
21572     68/push 0x11/imm32/alloc-id:fake:payload
21573     89/<- %ecx 4/r32/esp
21574 $test-emit-subx-stmt-primitive:initialize-var:
21575     # var var-foo/ecx: (payload var) = var(type)
21576     68/push 0/imm32/no-register
21577     68/push 0/imm32/no-register
21578     68/push -8/imm32/stack-offset
21579     68/push 1/imm32/block-depth
21580     51/push-ecx/type
21581     68/push 0x11/imm32/alloc-id:fake
21582     68/push 0/imm32/name
21583     68/push 0/imm32/name
21584     68/push 0x11/imm32/alloc-id:fake:payload
21585     89/<- %ecx 4/r32/esp
21586 $test-emit-subx-stmt-primitive:initialize-var-name:
21587     # var-foo->name = "foo"
21588     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21589     (copy-array Heap "foo" %eax)
21590 $test-emit-subx-stmt-primitive:initialize-stmt-var:
21591     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
21592     68/push 0/imm32/is-deref:false
21593     68/push 0/imm32/next
21594     68/push 0/imm32/next
21595     51/push-ecx/var-foo
21596     68/push 0x11/imm32/alloc-id:fake
21597     68/push 0x11/imm32/alloc-id:fake:payload
21598     89/<- %ebx 4/r32/esp
21599 $test-emit-subx-stmt-primitive:initialize-stmt:
21600     # var stmt/esi: (addr statement)
21601     68/push 0/imm32/no-outputs
21602     68/push 0/imm32/no-outputs
21603     53/push-ebx/inouts
21604     68/push 0x11/imm32/alloc-id:fake
21605     68/push 0/imm32/operation
21606     68/push 0/imm32/operation
21607     68/push 1/imm32/tag
21608     89/<- %esi 4/r32/esp
21609 $test-emit-subx-stmt-primitive:initialize-stmt-operation:
21610     # stmt->operation = "increment"
21611     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21612     (copy-array Heap "increment" %eax)
21613 $test-emit-subx-stmt-primitive:initialize-primitive:
21614     # var primitives/ebx: (addr primitive)
21615     68/push 0/imm32/next
21616     68/push 0/imm32/next
21617     68/push 0/imm32/output-is-write-only
21618     68/push 0/imm32/no-disp32
21619     68/push 0/imm32/no-imm8
21620     68/push 0/imm32/no-imm32
21621     68/push 0/imm32/no-r32
21622     68/push 1/imm32/rm32-is-first-inout
21623     68/push 0/imm32/subx-name
21624     68/push 0/imm32/subx-name
21625     68/push 0/imm32/no-outputs
21626     68/push 0/imm32/no-outputs
21627     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
21628     68/push 0x11/imm32/alloc-id:fake
21629     68/push 0/imm32/name
21630     68/push 0/imm32/name
21631     89/<- %ebx 4/r32/esp
21632 $test-emit-subx-stmt-primitive:initialize-primitive-name:
21633     # primitives->name = "increment"
21634     (copy-array Heap "increment" %ebx)  # Primitive-name
21635 $test-emit-subx-stmt-primitive:initialize-primitive-subx-name:
21636     # primitives->subx-name = "ff 0/subop/increment"
21637     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
21638     (copy-array Heap "ff 0/subop/increment" %eax)
21639     # convert
21640     c7 0/subop/copy *Curr-block-depth 0/imm32
21641     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
21642     (flush _test-output-buffered-file)
21643 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
21649     # check output
21650     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-stmt-primitive")
21651     # . epilogue
21652     89/<- %esp 5/r32/ebp
21653     5d/pop-to-ebp
21654     c3/return
21655 
21656 test-emit-subx-stmt-primitive-register:
21657     # Primitive operation on a variable in a register.
21658     #   foo <- increment
21659     # =>
21660     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
21661     #
21662     # There's a variable on the var stack as follows:
21663     #   name: 'foo'
21664     #   type: int
21665     #   register: 'eax'
21666     #
21667     # There's a primitive with this info:
21668     #   name: 'increment'
21669     #   out: int/reg
21670     #   value: 'ff 0/subop/increment'
21671     #
21672     # . prologue
21673     55/push-ebp
21674     89/<- %ebp 4/r32/esp
21675     # setup
21676     (clear-stream _test-output-stream)
21677     (clear-stream $_test-output-buffered-file->buffer)
21678 $test-emit-subx-stmt-primitive-register:initialize-type:
21679     # var type/ecx: (payload type-tree) = int
21680     68/push 0/imm32/right:null
21681     68/push 0/imm32/right:null
21682     68/push 0/imm32/left:unused
21683     68/push 1/imm32/value:int
21684     68/push 1/imm32/is-atom?:true
21685     68/push 0x11/imm32/alloc-id:fake:payload
21686     89/<- %ecx 4/r32/esp
21687 $test-emit-subx-stmt-primitive-register:initialize-var:
21688     # var var-foo/ecx: (payload var)
21689     68/push 0/imm32/register
21690     68/push 0/imm32/register
21691     68/push 0/imm32/no-stack-offset
21692     68/push 1/imm32/block-depth
21693     51/push-ecx
21694     68/push 0x11/imm32/alloc-id:fake
21695     68/push 0/imm32/name
21696     68/push 0/imm32/name
21697     68/push 0x11/imm32/alloc-id:fake:payload
21698     89/<- %ecx 4/r32/esp
21699 $test-emit-subx-stmt-primitive-register:initialize-var-name:
21700     # var-foo->name = "foo"
21701     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21702     (copy-array Heap "foo" %eax)
21703 $test-emit-subx-stmt-primitive-register:initialize-var-register:
21704     # var-foo->register = "eax"
21705     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
21706     (copy-array Heap "eax" %eax)
21707 $test-emit-subx-stmt-primitive-register:initialize-stmt-var:
21708     # var operand/ebx: (payload stmt-var)
21709     68/push 0/imm32/is-deref:false
21710     68/push 0/imm32/next
21711     68/push 0/imm32/next
21712     51/push-ecx/var-foo
21713     68/push 0x11/imm32/alloc-id:fake
21714     68/push 0x11/imm32/alloc-id:fake:payload
21715     89/<- %ebx 4/r32/esp
21716 $test-emit-subx-stmt-primitive-register:initialize-stmt:
21717     # var stmt/esi: (addr statement)
21718     53/push-ebx/outputs
21719     68/push 0x11/imm32/alloc-id:fake
21720     68/push 0/imm32/no-inouts
21721     68/push 0/imm32/no-inouts
21722     68/push 0/imm32/operation
21723     68/push 0/imm32/operation
21724     68/push 1/imm32
21725     89/<- %esi 4/r32/esp
21726 $test-emit-subx-stmt-primitive-register:initialize-stmt-operation:
21727     # stmt->operation = "increment"
21728     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21729     (copy-array Heap "increment" %eax)
21730 $test-emit-subx-stmt-primitive-register:initialize-formal-var:
21731     # var formal-var/ebx: (payload var)
21732     68/push 0/imm32/register
21733     68/push 0/imm32/register
21734     68/push 0/imm32/no-stack-offset
21735     68/push 1/imm32/block-depth
21736     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
21737     68/push 0x11/imm32/alloc-id:fake
21738     68/push 0/imm32/name
21739     68/push 0/imm32/name
21740     68/push 0x11/imm32/alloc-id:fake:payload
21741     89/<- %ebx 4/r32/esp
21742 $test-emit-subx-stmt-primitive-register:initialize-formal-var-name:
21743     # formal-var->name = "dummy"
21744     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
21745     (copy-array Heap "dummy" %eax)
21746 $test-emit-subx-stmt-primitive-register:initialize-formal-register:
21747     # formal-var->register = "*"
21748     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
21749     (copy-array Heap "*" %eax)  # Any-register
21750 $test-emit-subx-stmt-primitive-register:initialize-var-list:
21751     # var formal-outputs/ebx: (payload list var)
21752     68/push 0/imm32/next
21753     68/push 0/imm32/next
21754     53/push-ebx/formal-var
21755     68/push 0x11/imm32/alloc-id:fake
21756     68/push 0x11/imm32/alloc-id:fake:payload
21757     89/<- %ebx 4/r32/esp
21758 $test-emit-subx-stmt-primitive-register:initialize-primitive:
21759     # var primitives/ebx: (addr primitive)
21760     68/push 0/imm32/next
21761     68/push 0/imm32/next
21762     68/push 0/imm32/output-is-write-only
21763     68/push 0/imm32/no-disp32
21764     68/push 0/imm32/no-imm8
21765     68/push 0/imm32/no-imm32
21766     68/push 0/imm32/no-r32
21767     68/push 3/imm32/rm32-is-first-output
21768     68/push 0/imm32/subx-name
21769     68/push 0/imm32/subx-name
21770     53/push-ebx/outputs
21771     68/push 0x11/imm32/alloc-id:fake
21772     68/push 0/imm32/no-inouts
21773     68/push 0/imm32/no-inouts
21774     68/push 0/imm32/name
21775     68/push 0/imm32/name
21776     89/<- %ebx 4/r32/esp
21777 $test-emit-subx-stmt-primitive-register:initialize-primitive-name:
21778     # primitives->name = "increment"
21779     (copy-array Heap "increment" %ebx)  # Primitive-name
21780 $test-emit-subx-stmt-primitive-register:initialize-primitive-subx-name:
21781     # primitives->subx-name = "ff 0/subop/increment"
21782     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
21783     (copy-array Heap "ff 0/subop/increment" %eax)
21784     # convert
21785     c7 0/subop/copy *Curr-block-depth 0/imm32
21786     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
21787     (flush _test-output-buffered-file)
21788 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
21794     # check output
21795     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-primitive-register")
21796     # . epilogue
21797     89/<- %esp 5/r32/ebp
21798     5d/pop-to-ebp
21799     c3/return
21800 
21801 test-emit-subx-stmt-select-primitive:
21802     # Select the right primitive between overloads.
21803     #   foo <- increment
21804     # =>
21805     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
21806     #
21807     # There's a variable on the var stack as follows:
21808     #   name: 'foo'
21809     #   type: int
21810     #   register: 'eax'
21811     #
21812     # There's two primitives, as follows:
21813     #   - name: 'increment'
21814     #     out: int/reg
21815     #     value: 'ff 0/subop/increment'
21816     #   - name: 'increment'
21817     #     inout: int/mem
21818     #     value: 'ff 0/subop/increment'
21819     #
21820     # . prologue
21821     55/push-ebp
21822     89/<- %ebp 4/r32/esp
21823     # setup
21824     (clear-stream _test-output-stream)
21825     (clear-stream $_test-output-buffered-file->buffer)
21826 $test-emit-subx-stmt-select-primitive:initialize-type:
21827     # var type/ecx: (payload type-tree) = int
21828     68/push 0/imm32/right:null
21829     68/push 0/imm32/right:null
21830     68/push 0/imm32/left:unused
21831     68/push 1/imm32/value:int
21832     68/push 1/imm32/is-atom?:true
21833     68/push 0x11/imm32/alloc-id:fake:payload
21834     89/<- %ecx 4/r32/esp
21835 $test-emit-subx-stmt-select-primitive:initialize-var:
21836     # var var-foo/ecx: (payload var)
21837     68/push 0/imm32/register
21838     68/push 0/imm32/register
21839     68/push 0/imm32/no-stack-offset
21840     68/push 1/imm32/block-depth
21841     51/push-ecx
21842     68/push 0x11/imm32/alloc-id:fake
21843     68/push 0/imm32/name
21844     68/push 0/imm32/name
21845     68/push 0x11/imm32/alloc-id:fake:payload
21846     89/<- %ecx 4/r32/esp
21847 $test-emit-subx-stmt-select-primitive:initialize-var-name:
21848     # var-foo->name = "foo"
21849     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21850     (copy-array Heap "foo" %eax)
21851 $test-emit-subx-stmt-select-primitive:initialize-var-register:
21852     # var-foo->register = "eax"
21853     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
21854     (copy-array Heap "eax" %eax)
21855 $test-emit-subx-stmt-select-primitive:initialize-stmt-var:
21856     # var operand/ebx: (payload stmt-var)
21857     68/push 0/imm32/is-deref:false
21858     68/push 0/imm32/next
21859     68/push 0/imm32/next
21860     51/push-ecx/var-foo
21861     68/push 0x11/imm32/alloc-id:fake
21862     68/push 0x11/imm32/alloc-id:fake:payload
21863     89/<- %ebx 4/r32/esp
21864 $test-emit-subx-stmt-select-primitive:initialize-stmt:
21865     # var stmt/esi: (addr statement)
21866     53/push-ebx/outputs
21867     68/push 0x11/imm32/alloc-id:fake
21868     68/push 0/imm32/no-inouts
21869     68/push 0/imm32/no-inouts
21870     68/push 0/imm32/operation
21871     68/push 0/imm32/operation
21872     68/push 1/imm32
21873     89/<- %esi 4/r32/esp
21874 $test-emit-subx-stmt-select-primitive:initialize-stmt-operation:
21875     # stmt->operation = "increment"
21876     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21877     (copy-array Heap "increment" %eax)
21878 $test-emit-subx-stmt-select-primitive:initialize-formal-var:
21879     # var formal-var/ebx: (payload var)
21880     68/push 0/imm32/register
21881     68/push 0/imm32/register
21882     68/push 0/imm32/no-stack-offset
21883     68/push 1/imm32/block-depth
21884     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
21885     68/push 0x11/imm32/alloc-id:fake
21886     68/push 0/imm32/name
21887     68/push 0/imm32/name
21888     68/push 0x11/imm32/alloc-id:fake:payload
21889     89/<- %ebx 4/r32/esp
21890 $test-emit-subx-stmt-select-primitive:initialize-formal-var-name:
21891     # formal-var->name = "dummy"
21892     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
21893     (copy-array Heap "dummy" %eax)
21894 $test-emit-subx-stmt-select-primitive:initialize-formal-register:
21895     # formal-var->register = "*"
21896     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
21897     (copy-array Heap "*" %eax)  # Any-register
21898 $test-emit-subx-stmt-select-primitive:initialize-var-list:
21899     # var formal-outputs/ebx: (payload list var)
21900     68/push 0/imm32/next
21901     68/push 0/imm32/next
21902     53/push-ebx/formal-var
21903     68/push 0x11/imm32/alloc-id:fake
21904     68/push 0x11/imm32/alloc-id:fake:payload
21905     89/<- %ebx 4/r32/esp
21906 $test-emit-subx-stmt-select-primitive:initialize-primitive2:
21907     # var primitive2/edi: (payload primitive)
21908     68/push 0/imm32/next
21909     68/push 0/imm32/next
21910     68/push 0/imm32/output-is-write-only
21911     68/push 0/imm32/no-disp32
21912     68/push 0/imm32/no-imm8
21913     68/push 0/imm32/no-imm32
21914     68/push 0/imm32/no-r32
21915     68/push 3/imm32/rm32-is-first-output
21916     68/push 0/imm32/subx-name
21917     68/push 0/imm32/subx-name
21918     53/push-ebx/outputs
21919     68/push 0x11/imm32/alloc-id:fake
21920     68/push 0/imm32/no-inouts
21921     68/push 0/imm32/no-inouts
21922     68/push 0/imm32/name
21923     68/push 0/imm32/name
21924     68/push 0x11/imm32/alloc-id:fake:payload
21925     89/<- %edi 4/r32/esp
21926 $test-emit-subx-stmt-select-primitive:initialize-primitive2-name:
21927     # primitives->name = "increment"
21928     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
21929     (copy-array Heap "increment" %eax)
21930 $test-emit-subx-stmt-select-primitive:initialize-primitive2-subx-name:
21931     # primitives->subx-name = "ff 0/subop/increment"
21932     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
21933     (copy-array Heap "ff 0/subop/increment" %eax)
21934 $test-emit-subx-stmt-select-primitive:initialize-primitive:
21935     # var primitives/ebx: (addr primitive)
21936     57/push-edi
21937     68/push 0x11/imm32/alloc-id:fake
21938     68/push 0/imm32/output-is-write-only
21939     68/push 0/imm32/no-disp32
21940     68/push 0/imm32/no-imm8
21941     68/push 0/imm32/no-imm32
21942     68/push 0/imm32/no-r32
21943     68/push 1/imm32/rm32-is-first-inout
21944     68/push 0/imm32/subx-name
21945     68/push 0/imm32/subx-name
21946     68/push 0/imm32/no-outputs
21947     68/push 0/imm32/no-outputs
21948     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
21949     68/push 0x11/imm32/alloc-id:fake
21950     68/push 0/imm32/name
21951     68/push 0/imm32/name
21952     89/<- %ebx 4/r32/esp
21953 $test-emit-subx-stmt-select-primitive:initialize-primitive-name:
21954     # primitives->name = "increment"
21955     (copy-array Heap "increment" %ebx)  # Primitive-name
21956 $test-emit-subx-stmt-select-primitive:initialize-primitive-subx-name:
21957     # primitives->subx-name = "ff 0/subop/increment"
21958     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
21959     (copy-array Heap "ff 0/subop/increment" %eax)
21960     # convert
21961     c7 0/subop/copy *Curr-block-depth 0/imm32
21962     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
21963     (flush _test-output-buffered-file)
21964 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
21970     # check output
21971     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive")
21972     # . epilogue
21973     89/<- %esp 5/r32/ebp
21974     5d/pop-to-ebp
21975     c3/return
21976 
21977 test-emit-subx-stmt-select-primitive-2:
21978     # Select the right primitive between overloads.
21979     #   increment foo
21980     # =>
21981     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
21982     #
21983     # There's a variable on the var stack as follows:
21984     #   name: 'foo'
21985     #   type: int
21986     #   register: 'eax'
21987     #
21988     # There's two primitives, as follows:
21989     #   - name: 'increment'
21990     #     out: int/reg
21991     #     value: 'ff 0/subop/increment'
21992     #   - name: 'increment'
21993     #     inout: int/mem
21994     #     value: 'ff 0/subop/increment'
21995     #
21996     # . prologue
21997     55/push-ebp
21998     89/<- %ebp 4/r32/esp
21999     # setup
22000     (clear-stream _test-output-stream)
22001     (clear-stream $_test-output-buffered-file->buffer)
22002 $test-emit-subx-stmt-select-primitive-2:initialize-type:
22003     # var type/ecx: (payload type-tree) = int
22004     68/push 0/imm32/right:null
22005     68/push 0/imm32/right:null
22006     68/push 0/imm32/left:unused
22007     68/push 1/imm32/value:int
22008     68/push 1/imm32/is-atom?:true
22009     68/push 0x11/imm32/alloc-id:fake:payload
22010     89/<- %ecx 4/r32/esp
22011 $test-emit-subx-stmt-select-primitive-2:initialize-var:
22012     # var var-foo/ecx: (payload var)
22013     68/push 0/imm32/register
22014     68/push 0/imm32/register
22015     68/push 0/imm32/no-stack-offset
22016     68/push 1/imm32/block-depth
22017     51/push-ecx
22018     68/push 0x11/imm32/alloc-id:fake
22019     68/push 0/imm32/name
22020     68/push 0/imm32/name
22021     68/push 0x11/imm32/alloc-id:fake:payload
22022     89/<- %ecx 4/r32/esp
22023 $test-emit-subx-stmt-select-primitive-2:initialize-var-name:
22024     # var-foo->name = "foo"
22025     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22026     (copy-array Heap "foo" %eax)
22027 $test-emit-subx-stmt-select-primitive-2:initialize-var-register:
22028     # var-foo->register = "eax"
22029     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
22030     (copy-array Heap "eax" %eax)
22031 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-var:
22032     # var operand/ebx: (payload stmt-var)
22033     68/push 0/imm32/is-deref:false
22034     68/push 0/imm32/next
22035     68/push 0/imm32/next
22036     51/push-ecx/var-foo
22037     68/push 0x11/imm32/alloc-id:fake
22038     68/push 0x11/imm32/alloc-id:fake:payload
22039     89/<- %ebx 4/r32/esp
22040 $test-emit-subx-stmt-select-primitive-2:initialize-stmt:
22041     # var stmt/esi: (addr statement)
22042     68/push 0/imm32/no-outputs
22043     68/push 0/imm32/no-outputs
22044     53/push-ebx/inouts
22045     68/push 0x11/imm32/alloc-id:fake
22046     68/push 0/imm32/operation
22047     68/push 0/imm32/operation
22048     68/push 1/imm32
22049     89/<- %esi 4/r32/esp
22050 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-operation:
22051     # stmt->operation = "increment"
22052     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22053     (copy-array Heap "increment" %eax)
22054 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var:
22055     # var formal-var/ebx: (payload var)
22056     68/push 0/imm32/register
22057     68/push 0/imm32/register
22058     68/push 0/imm32/no-stack-offset
22059     68/push 1/imm32/block-depth
22060     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
22061     68/push 0x11/imm32/alloc-id:fake
22062     68/push 0/imm32/name
22063     68/push 0/imm32/name
22064     68/push 0x11/imm32/alloc-id:fake:payload
22065     89/<- %ebx 4/r32/esp
22066 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var-name:
22067     # formal-var->name = "dummy"
22068     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
22069     (copy-array Heap "dummy" %eax)
22070 $test-emit-subx-stmt-select-primitive-2:initialize-formal-register:
22071     # formal-var->register = "*"
22072     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
22073     (copy-array Heap "*" %eax)  # Any-register
22074 $test-emit-subx-stmt-select-primitive-2:initialize-var-list:
22075     # var formal-outputs/ebx: (payload list stmt-var)
22076     68/push 0/imm32/next
22077     68/push 0/imm32/next
22078     53/push-ebx/formal-var
22079     68/push 0x11/imm32/alloc-id:fake
22080     68/push 0x11/imm32/alloc-id:fake:payload
22081     89/<- %ebx 4/r32/esp
22082 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2:
22083     # var primitive2/edi: (payload primitive)
22084     68/push 0/imm32/next
22085     68/push 0/imm32/next
22086     68/push 0/imm32/output-is-write-only
22087     68/push 0/imm32/no-disp32
22088     68/push 0/imm32/no-imm8
22089     68/push 0/imm32/no-imm32
22090     68/push 0/imm32/no-r32
22091     68/push 3/imm32/rm32-is-first-output
22092     68/push 0/imm32/subx-name
22093     68/push 0/imm32/subx-name
22094     53/push-ebx/outputs
22095     68/push 0x11/imm32/alloc-id:fake
22096     68/push 0/imm32/no-inouts
22097     68/push 0/imm32/no-inouts
22098     68/push 0/imm32/name
22099     68/push 0/imm32/name
22100     68/push 0x11/imm32/alloc-id:fake:payload
22101     89/<- %edi 4/r32/esp
22102 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-name:
22103     # primitives->name = "increment"
22104     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
22105     (copy-array Heap "increment" %eax)
22106 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-subx-name:
22107     # primitives->subx-name = "ff 0/subop/increment"
22108     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
22109     (copy-array Heap "ff 0/subop/increment" %eax)
22110 $test-emit-subx-stmt-select-primitive-2:initialize-primitive:
22111     # var primitives/ebx: (addr primitive)
22112     57/push-edi
22113     68/push 0x11/imm32/alloc-id:fake
22114     68/push 0/imm32/output-is-write-only
22115     68/push 0/imm32/no-disp32
22116     68/push 0/imm32/no-imm8
22117     68/push 0/imm32/no-imm32
22118     68/push 0/imm32/no-r32
22119     68/push 1/imm32/rm32-is-first-inout
22120     68/push 0/imm32/subx-name
22121     68/push 0/imm32/subx-name
22122     68/push 0/imm32/no-outputs
22123     68/push 0/imm32/no-outputs
22124     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
22125     68/push 0x11/imm32/alloc-id:fake
22126     68/push 0/imm32/name
22127     68/push 0/imm32/name
22128     89/<- %ebx 4/r32/esp
22129 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-name:
22130     # primitives->name = "increment"
22131     (copy-array Heap "increment" %ebx)  # Primitive-name
22132 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-subx-name:
22133     # primitives->subx-name = "ff 0/subop/increment"
22134     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
22135     (copy-array Heap "ff 0/subop/increment" %eax)
22136     # convert
22137     c7 0/subop/copy *Curr-block-depth 0/imm32
22138     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
22139     (flush _test-output-buffered-file)
22140 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
22146     # check output
22147     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive-2")
22148     # . epilogue
22149     89/<- %esp 5/r32/ebp
22150     5d/pop-to-ebp
22151     c3/return
22152 
22153 test-increment-register:
22154     # Select the right register between overloads.
22155     #   foo <- increment
22156     # =>
22157     #   50/increment-eax
22158     #
22159     # There's a variable on the var stack as follows:
22160     #   name: 'foo'
22161     #   type: int
22162     #   register: 'eax'
22163     #
22164     # Primitives are the global definitions.
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-increment-register: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-increment-register:initialize-var:
22182     # var var-foo/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-increment-register:initialize-var-name:
22194     # var-foo->name = "foo"
22195     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22196     (copy-array Heap "foo" %eax)
22197 $test-increment-register:initialize-var-register:
22198     # var-foo->register = "eax"
22199     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
22200     (copy-array Heap "eax" %eax)
22201 $test-increment-register:initialize-stmt-var:
22202     # var operand/ebx: (payload stmt-var)
22203     68/push 0/imm32/is-deref:false
22204     68/push 0/imm32/next
22205     68/push 0/imm32/next
22206     51/push-ecx/var-foo
22207     68/push 0x11/imm32/alloc-id:fake
22208     68/push 0x11/imm32/alloc-id:fake:payload
22209     89/<- %ebx 4/r32/esp
22210 $test-increment-register:initialize-stmt:
22211     # var stmt/esi: (addr statement)
22212     53/push-ebx/outputs
22213     68/push 0x11/imm32/alloc-id:fake
22214     68/push 0/imm32/no-inouts
22215     68/push 0/imm32/no-inouts
22216     68/push 0/imm32/operation
22217     68/push 0/imm32/operation
22218     68/push 1/imm32
22219     89/<- %esi 4/r32/esp
22220 $test-increment-register:initialize-stmt-operation:
22221     # stmt->operation = "increment"
22222     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22223     (copy-array Heap "increment" %eax)
22224     # convert
22225     c7 0/subop/copy *Curr-block-depth 0/imm32
22226     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22227     (flush _test-output-buffered-file)
22228 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
22234     # check output
22235     (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register")
22236     # . epilogue
22237     89/<- %esp 5/r32/ebp
22238     5d/pop-to-ebp
22239     c3/return
22240 
22241 test-add-reg-to-reg:
22242     #   var1/reg <- add var2/reg
22243     # =>
22244     #   01/add-to %var1 var2
22245     #
22246     # . prologue
22247     55/push-ebp
22248     89/<- %ebp 4/r32/esp
22249     # setup
22250     (clear-stream _test-output-stream)
22251     (clear-stream $_test-output-buffered-file->buffer)
22252 $test-add-reg-to-reg:initialize-type:
22253     # var type/ecx: (payload type-tree) = int
22254     68/push 0/imm32/right:null
22255     68/push 0/imm32/right:null
22256     68/push 0/imm32/left:unused
22257     68/push 1/imm32/value:int
22258     68/push 1/imm32/is-atom?:true
22259     68/push 0x11/imm32/alloc-id:fake:payload
22260     89/<- %ecx 4/r32/esp
22261 $test-add-reg-to-reg:initialize-var1:
22262     # var var1/ecx: (payload var)
22263     68/push 0/imm32/register
22264     68/push 0/imm32/register
22265     68/push 0/imm32/no-stack-offset
22266     68/push 1/imm32/block-depth
22267     51/push-ecx
22268     68/push 0x11/imm32/alloc-id:fake
22269     68/push 0/imm32/name
22270     68/push 0/imm32/name
22271     68/push 0x11/imm32/alloc-id:fake:payload
22272     89/<- %ecx 4/r32/esp
22273 $test-add-reg-to-reg:initialize-var1-name:
22274     # var1->name = "var1"
22275     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22276     (copy-array Heap "var1" %eax)
22277 $test-add-reg-to-reg:initialize-var1-register:
22278     # var1->register = "eax"
22279     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
22280     (copy-array Heap "eax" %eax)
22281 $test-add-reg-to-reg:initialize-var2:
22282     # var var2/edx: (payload var)
22283     68/push 0/imm32/register
22284     68/push 0/imm32/register
22285     68/push 0/imm32/no-stack-offset
22286     68/push 1/imm32/block-depth
22287     ff 6/subop/push *(ecx+0x10)
22288     68/push 0x11/imm32/alloc-id:fake
22289     68/push 0/imm32/name
22290     68/push 0/imm32/name
22291     68/push 0x11/imm32/alloc-id:fake:payload
22292     89/<- %edx 4/r32/esp
22293 $test-add-reg-to-reg:initialize-var2-name:
22294     # var2->name = "var2"
22295     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
22296     (copy-array Heap "var2" %eax)
22297 $test-add-reg-to-reg:initialize-var2-register:
22298     # var2->register = "ecx"
22299     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
22300     (copy-array Heap "ecx" %eax)
22301 $test-add-reg-to-reg:initialize-inouts:
22302     # var inouts/esi: (payload stmt-var) = [var2]
22303     68/push 0/imm32/is-deref:false
22304     68/push 0/imm32/next
22305     68/push 0/imm32/next
22306     52/push-edx/var2
22307     68/push 0x11/imm32/alloc-id:fake
22308     68/push 0x11/imm32/alloc-id:fake:payload
22309     89/<- %esi 4/r32/esp
22310 $test-add-reg-to-reg:initialize-outputs:
22311     # var outputs/edi: (payload stmt-var) = [var1]
22312     68/push 0/imm32/is-deref:false
22313     68/push 0/imm32/next
22314     68/push 0/imm32/next
22315     51/push-ecx/var1
22316     68/push 0x11/imm32/alloc-id:fake
22317     68/push 0x11/imm32/alloc-id:fake:payload
22318     89/<- %edi 4/r32/esp
22319 $test-add-reg-to-reg:initialize-stmt:
22320     # var stmt/esi: (addr statement)
22321     68/push 0/imm32/next
22322     68/push 0/imm32/next
22323     57/push-edi/outputs
22324     68/push 0x11/imm32/alloc-id:fake
22325     56/push-esi/inouts
22326     68/push 0x11/imm32/alloc-id:fake
22327     68/push 0/imm32/operation
22328     68/push 0/imm32/operation
22329     68/push 1/imm32/tag:stmt1
22330     89/<- %esi 4/r32/esp
22331 $test-add-reg-to-reg:initialize-stmt-operation:
22332     # stmt->operation = "add"
22333     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22334     (copy-array Heap "add" %eax)
22335     # convert
22336     c7 0/subop/copy *Curr-block-depth 0/imm32
22337     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22338     (flush _test-output-buffered-file)
22339 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
22345     # check output
22346     (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg")
22347     # . epilogue
22348     89/<- %esp 5/r32/ebp
22349     5d/pop-to-ebp
22350     c3/return
22351 
22352 test-add-reg-to-mem:
22353     #   add-to var1 var2/reg
22354     # =>
22355     #   01/add-to *(ebp+__) var2
22356     #
22357     # . prologue
22358     55/push-ebp
22359     89/<- %ebp 4/r32/esp
22360     # setup
22361     (clear-stream _test-output-stream)
22362     (clear-stream $_test-output-buffered-file->buffer)
22363 $test-add-reg-to-mem:initialize-type:
22364     # var type/ecx: (payload type-tree) = int
22365     68/push 0/imm32/right:null
22366     68/push 0/imm32/right:null
22367     68/push 0/imm32/left:unused
22368     68/push 1/imm32/value:int
22369     68/push 1/imm32/is-atom?:true
22370     68/push 0x11/imm32/alloc-id:fake:payload
22371     89/<- %ecx 4/r32/esp
22372 $test-add-reg-to-mem:initialize-var1:
22373     # var var1/ecx: (payload var)
22374     68/push 0/imm32/register
22375     68/push 0/imm32/register
22376     68/push 8/imm32/stack-offset
22377     68/push 1/imm32/block-depth
22378     51/push-ecx
22379     68/push 0x11/imm32/alloc-id:fake
22380     68/push 0/imm32/name
22381     68/push 0/imm32/name
22382     68/push 0x11/imm32/alloc-id:fake:payload
22383     89/<- %ecx 4/r32/esp
22384 $test-add-reg-to-mem:initialize-var1-name:
22385     # var1->name = "var1"
22386     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22387     (copy-array Heap "var1" %eax)
22388 $test-add-reg-to-mem:initialize-var2:
22389     # var var2/edx: (payload var)
22390     68/push 0/imm32/register
22391     68/push 0/imm32/register
22392     68/push 0/imm32/no-stack-offset
22393     68/push 1/imm32/block-depth
22394     ff 6/subop/push *(ecx+0x10)
22395     68/push 0x11/imm32/alloc-id:fake
22396     68/push 0/imm32/name
22397     68/push 0/imm32/name
22398     68/push 0x11/imm32/alloc-id:fake:payload
22399     89/<- %edx 4/r32/esp
22400 $test-add-reg-to-mem:initialize-var2-name:
22401     # var2->name = "var2"
22402     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
22403     (copy-array Heap "var2" %eax)
22404 $test-add-reg-to-mem:initialize-var2-register:
22405     # var2->register = "ecx"
22406     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
22407     (copy-array Heap "ecx" %eax)
22408 $test-add-reg-to-mem:initialize-inouts:
22409     # var inouts/esi: (payload stmt-var) = [var2]
22410     68/push 0/imm32/is-deref:false
22411     68/push 0/imm32/next
22412     68/push 0/imm32/next
22413     52/push-edx/var2
22414     68/push 0x11/imm32/alloc-id:fake
22415     68/push 0x11/imm32/alloc-id:fake:payload
22416     89/<- %esi 4/r32/esp
22417     # inouts = [var1, var2]
22418     68/push 0/imm32/is-deref:false
22419     56/push-esi/next
22420     68/push 0x11/imm32/alloc-id:fake
22421     51/push-ecx/var1
22422     68/push 0x11/imm32/alloc-id:fake
22423     68/push 0x11/imm32/alloc-id:fake:payload
22424     89/<- %esi 4/r32/esp
22425 $test-add-reg-to-mem:initialize-stmt:
22426     # var stmt/esi: (addr statement)
22427     68/push 0/imm32/next
22428     68/push 0/imm32/next
22429     68/push 0/imm32/outputs
22430     68/push 0/imm32/outputs
22431     56/push-esi/inouts
22432     68/push 0x11/imm32/alloc-id:fake
22433     68/push 0/imm32/operation
22434     68/push 0/imm32/operation
22435     68/push 1/imm32/tag:stmt1
22436     89/<- %esi 4/r32/esp
22437 $test-add-reg-to-mem:initialize-stmt-operation:
22438     # stmt->operation = "add-to"
22439     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22440     (copy-array Heap "add-to" %eax)
22441     # convert
22442     c7 0/subop/copy *Curr-block-depth 0/imm32
22443     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22444     (flush _test-output-buffered-file)
22445 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
22451     # check output
22452     (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem")
22453     # . epilogue
22454     89/<- %esp 5/r32/ebp
22455     5d/pop-to-ebp
22456     c3/return
22457 
22458 test-add-mem-to-reg:
22459     #   var1/reg <- add var2
22460     # =>
22461     #   03/add *(ebp+__) var1
22462     #
22463     # . prologue
22464     55/push-ebp
22465     89/<- %ebp 4/r32/esp
22466     # setup
22467     (clear-stream _test-output-stream)
22468     (clear-stream $_test-output-buffered-file->buffer)
22469 $test-add-mem-to-reg:initialize-type:
22470     # var type/ecx: (payload type-tree) = int
22471     68/push 0/imm32/right:null
22472     68/push 0/imm32/right:null
22473     68/push 0/imm32/left:unused
22474     68/push 1/imm32/value:int
22475     68/push 1/imm32/is-atom?:true
22476     68/push 0x11/imm32/alloc-id:fake:payload
22477     89/<- %ecx 4/r32/esp
22478 $test-add-mem-to-reg:initialize-var:
22479     # var var1/ecx: (payload var)
22480     68/push 0/imm32/register
22481     68/push 0/imm32/register
22482     68/push 0/imm32/no-stack-offset
22483     68/push 1/imm32/block-depth
22484     51/push-ecx
22485     68/push 0x11/imm32/alloc-id:fake
22486     68/push 0/imm32/name
22487     68/push 0/imm32/name
22488     68/push 0x11/imm32/alloc-id:fake:payload
22489     89/<- %ecx 4/r32/esp
22490 $test-add-mem-to-reg:initialize-var-name:
22491     # var1->name = "foo"
22492     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22493     (copy-array Heap "var1" %eax)
22494 $test-add-mem-to-reg:initialize-var-register:
22495     # var1->register = "eax"
22496     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
22497     (copy-array Heap "eax" %eax)
22498 $test-add-mem-to-reg:initialize-var2:
22499     # var var2/edx: (payload var)
22500     68/push 0/imm32/register
22501     68/push 0/imm32/register
22502     68/push 8/imm32/stack-offset
22503     68/push 1/imm32/block-depth
22504     ff 6/subop/push *(ecx+0x10)
22505     68/push 0x11/imm32/alloc-id:fake
22506     68/push 0/imm32/name
22507     68/push 0/imm32/name
22508     68/push 0x11/imm32/alloc-id:fake:payload
22509     89/<- %edx 4/r32/esp
22510 $test-add-mem-to-reg:initialize-var2-name:
22511     # var2->name = "var2"
22512     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
22513     (copy-array Heap "var2" %eax)
22514 $test-add-mem-to-reg:initialize-inouts:
22515     # var inouts/esi: (payload stmt-var) = [var2]
22516     68/push 0/imm32/is-deref:false
22517     68/push 0/imm32/next
22518     68/push 0/imm32/next
22519     52/push-edx/var2
22520     68/push 0x11/imm32/alloc-id:fake
22521     68/push 0x11/imm32/alloc-id:fake:payload
22522     89/<- %esi 4/r32/esp
22523 $test-add-mem-to-reg:initialize-outputs:
22524     # var outputs/edi: (payload stmt-var) = [var1]
22525     68/push 0/imm32/is-deref:false
22526     68/push 0/imm32/next
22527     68/push 0/imm32/next
22528     51/push-ecx/var1
22529     68/push 0x11/imm32/alloc-id:fake
22530     68/push 0x11/imm32/alloc-id:fake:payload
22531     89/<- %edi 4/r32/esp
22532 $test-add-mem-to-reg:initialize-stmt:
22533     # var stmt/esi: (addr statement)
22534     68/push 0/imm32/next
22535     68/push 0/imm32/next
22536     57/push-edi/outputs
22537     68/push 0x11/imm32/alloc-id:fake
22538     56/push-esi/inouts
22539     68/push 0x11/imm32/alloc-id:fake
22540     68/push 0/imm32/operation
22541     68/push 0/imm32/operation
22542     68/push 1/imm32/tag:stmt1
22543     89/<- %esi 4/r32/esp
22544 $test-add-mem-to-reg:initialize-stmt-operation:
22545     # stmt->operation = "add"
22546     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22547     (copy-array Heap "add" %eax)
22548     # convert
22549     c7 0/subop/copy *Curr-block-depth 0/imm32
22550     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22551     (flush _test-output-buffered-file)
22552 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
22558     # check output
22559     (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg")
22560     # . epilogue
22561     89/<- %esp 5/r32/ebp
22562     5d/pop-to-ebp
22563     c3/return
22564 
22565 test-add-literal-to-eax:
22566     #   var1/eax <- add 0x34
22567     # =>
22568     #   05/add-to-eax 0x34/imm32
22569     #
22570     # . prologue
22571     55/push-ebp
22572     89/<- %ebp 4/r32/esp
22573     # setup
22574     (clear-stream _test-output-stream)
22575     (clear-stream $_test-output-buffered-file->buffer)
22576 $test-add-literal-to-eax:initialize-var-type:
22577     # var type/ecx: (payload type-tree) = int
22578     68/push 0/imm32/right:null
22579     68/push 0/imm32/right:null
22580     68/push 0/imm32/left:unused
22581     68/push 1/imm32/value:int
22582     68/push 1/imm32/is-atom?:true
22583     68/push 0x11/imm32/alloc-id:fake:payload
22584     89/<- %ecx 4/r32/esp
22585 $test-add-literal-to-eax:initialize-var:
22586     # var v/ecx: (payload var)
22587     68/push 0/imm32/register
22588     68/push 0/imm32/register
22589     68/push 0/imm32/no-stack-offset
22590     68/push 1/imm32/block-depth
22591     51/push-ecx
22592     68/push 0x11/imm32/alloc-id:fake
22593     68/push 0/imm32/name
22594     68/push 0/imm32/name
22595     68/push 0x11/imm32/alloc-id:fake:payload
22596     89/<- %ecx 4/r32/esp
22597 $test-add-literal-to-eax:initialize-var-name:
22598     # v->name = "v"
22599     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22600     (copy-array Heap "v" %eax)
22601 $test-add-literal-to-eax:initialize-var-register:
22602     # v->register = "eax"
22603     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
22604     (copy-array Heap "eax" %eax)
22605 $test-add-literal-to-eax:initialize-literal-type:
22606     # var type/edx: (payload type-tree) = literal
22607     68/push 0/imm32/right:null
22608     68/push 0/imm32/right:null
22609     68/push 0/imm32/left:unused
22610     68/push 0/imm32/value:literal
22611     68/push 1/imm32/is-atom?:true
22612     68/push 0x11/imm32/alloc-id:fake:payload
22613     89/<- %edx 4/r32/esp
22614 $test-add-literal-to-eax:initialize-literal:
22615     # var l/edx: (payload var)
22616     68/push 0/imm32/register
22617     68/push 0/imm32/register
22618     68/push 0/imm32/no-stack-offset
22619     68/push 1/imm32/block-depth
22620     52/push-edx
22621     68/push 0x11/imm32/alloc-id:fake
22622     68/push 0/imm32/name
22623     68/push 0/imm32/name
22624     68/push 0x11/imm32/alloc-id:fake:payload
22625     89/<- %edx 4/r32/esp
22626 $test-add-literal-to-eax:initialize-literal-value:
22627     # l->name = "0x34"
22628     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
22629     (copy-array Heap "0x34" %eax)
22630 $test-add-literal-to-eax:initialize-inouts:
22631     # var inouts/esi: (payload stmt-var) = [l]
22632     68/push 0/imm32/is-deref:false
22633     68/push 0/imm32/next
22634     68/push 0/imm32/next
22635     52/push-edx/l
22636     68/push 0x11/imm32/alloc-id:fake
22637     68/push 0x11/imm32/alloc-id:fake:payload
22638     89/<- %esi 4/r32/esp
22639 $test-add-literal-to-eax:initialize-outputs:
22640     # var outputs/edi: (payload stmt-var) = [v]
22641     68/push 0/imm32/is-deref:false
22642     68/push 0/imm32/next
22643     68/push 0/imm32/next
22644     51/push-ecx/v
22645     68/push 0x11/imm32/alloc-id:fake
22646     68/push 0x11/imm32/alloc-id:fake:payload
22647     89/<- %edi 4/r32/esp
22648 $test-add-literal-to-eax:initialize-stmt:
22649     # var stmt/esi: (addr statement)
22650     68/push 0/imm32/next
22651     68/push 0/imm32/next
22652     57/push-edi/outputs
22653     68/push 0x11/imm32/alloc-id:fake
22654     56/push-esi/inouts
22655     68/push 0x11/imm32/alloc-id:fake
22656     68/push 0/imm32/operation
22657     68/push 0/imm32/operation
22658     68/push 1/imm32/tag:stmt1
22659     89/<- %esi 4/r32/esp
22660 $test-add-literal-to-eax:initialize-stmt-operation:
22661     # stmt->operation = "add"
22662     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22663     (copy-array Heap "add" %eax)
22664     # convert
22665     c7 0/subop/copy *Curr-block-depth 0/imm32
22666     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22667     (flush _test-output-buffered-file)
22668 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
22674     # check output
22675     (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax")
22676     # . epilogue
22677     89/<- %esp 5/r32/ebp
22678     5d/pop-to-ebp
22679     c3/return
22680 
22681 test-add-literal-to-reg:
22682     #   var1/ecx <- add 0x34
22683     # =>
22684     #   81 0/subop/add %ecx 0x34/imm32
22685     #
22686     # . prologue
22687     55/push-ebp
22688     89/<- %ebp 4/r32/esp
22689     # setup
22690     (clear-stream _test-output-stream)
22691     (clear-stream $_test-output-buffered-file->buffer)
22692 $test-add-literal-to-reg:initialize-var-type:
22693     # var type/ecx: (payload type-tree) = int
22694     68/push 0/imm32/right:null
22695     68/push 0/imm32/right:null
22696     68/push 0/imm32/left:unused
22697     68/push 1/imm32/value:int
22698     68/push 1/imm32/is-atom?:true
22699     68/push 0x11/imm32/alloc-id:fake:payload
22700     89/<- %ecx 4/r32/esp
22701 $test-add-literal-to-reg:initialize-var:
22702     # var v/ecx: (payload var)
22703     68/push 0/imm32/register
22704     68/push 0/imm32/register
22705     68/push 0/imm32/no-stack-offset
22706     68/push 1/imm32/block-depth
22707     51/push-ecx
22708     68/push 0x11/imm32/alloc-id:fake
22709     68/push 0/imm32/name
22710     68/push 0/imm32/name
22711     68/push 0x11/imm32/alloc-id:fake:payload
22712     89/<- %ecx 4/r32/esp
22713 $test-add-literal-to-reg:initialize-var-name:
22714     # v->name = "v"
22715     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22716     (copy-array Heap "v" %eax)
22717 $test-add-literal-to-reg:initialize-var-register:
22718     # v->register = "ecx"
22719     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
22720     (copy-array Heap "ecx" %eax)
22721 $test-add-literal-to-reg:initialize-literal-type:
22722     # var type/edx: (payload type-tree) = literal
22723     68/push 0/imm32/right:null
22724     68/push 0/imm32/right:null
22725     68/push 0/imm32/left:unused
22726     68/push 0/imm32/value:literal
22727     68/push 1/imm32/is-atom?:true
22728     68/push 0x11/imm32/alloc-id:fake:payload
22729     89/<- %edx 4/r32/esp
22730 $test-add-literal-to-reg:initialize-literal:
22731     # var l/edx: (payload var)
22732     68/push 0/imm32/register
22733     68/push 0/imm32/register
22734     68/push 0/imm32/no-stack-offset
22735     68/push 1/imm32/block-depth
22736     52/push-edx
22737     68/push 0x11/imm32/alloc-id:fake
22738     68/push 0/imm32/name
22739     68/push 0/imm32/name
22740     68/push 0x11/imm32/alloc-id:fake:payload
22741     89/<- %edx 4/r32/esp
22742 $test-add-literal-to-reg:initialize-literal-value:
22743     # l->name = "0x34"
22744     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
22745     (copy-array Heap "0x34" %eax)
22746 $test-add-literal-to-reg:initialize-inouts:
22747     # var inouts/esi: (payload stmt-var) = [l]
22748     68/push 0/imm32/is-deref:false
22749     68/push 0/imm32/next
22750     68/push 0/imm32/next
22751     52/push-edx/l
22752     68/push 0x11/imm32/alloc-id:fake
22753     68/push 0x11/imm32/alloc-id:fake:payload
22754     89/<- %esi 4/r32/esp
22755 $test-add-literal-to-reg:initialize-outputs:
22756     # var outputs/edi: (payload stmt-var) = [v]
22757     68/push 0/imm32/is-deref:false
22758     68/push 0/imm32/next
22759     68/push 0/imm32/next
22760     51/push-ecx/v
22761     68/push 0x11/imm32/alloc-id:fake
22762     68/push 0x11/imm32/alloc-id:fake:payload
22763     89/<- %edi 4/r32/esp
22764 $test-add-literal-to-reg:initialize-stmt:
22765     # var stmt/esi: (addr statement)
22766     68/push 0/imm32/next
22767     68/push 0/imm32/next
22768     57/push-edi/outputs
22769     68/push 0x11/imm32/alloc-id:fake
22770     56/push-esi/inouts
22771     68/push 0x11/imm32/alloc-id:fake
22772     68/push 0/imm32/operation
22773     68/push 0/imm32/operation
22774     68/push 1/imm32/tag:stmt1
22775     89/<- %esi 4/r32/esp
22776 $test-add-literal-to-reg:initialize-stmt-operation:
22777     # stmt->operation = "add"
22778     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22779     (copy-array Heap "add" %eax)
22780     # convert
22781     c7 0/subop/copy *Curr-block-depth 0/imm32
22782     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22783     (flush _test-output-buffered-file)
22784 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
22790     # check output
22791     (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg")
22792     # . epilogue
22793     89/<- %esp 5/r32/ebp
22794     5d/pop-to-ebp
22795     c3/return
22796 
22797 test-add-literal-to-mem:
22798     #   add-to var1, 0x34
22799     # =>
22800     #   81 0/subop/add %eax 0x34/imm32
22801     #
22802     # . prologue
22803     55/push-ebp
22804     89/<- %ebp 4/r32/esp
22805     # setup
22806     (clear-stream _test-output-stream)
22807     (clear-stream $_test-output-buffered-file->buffer)
22808 $test-add-literal-to-mem:initialize-type:
22809     # var type/ecx: (payload type-tree) = int
22810     68/push 0/imm32/right:null
22811     68/push 0/imm32/right:null
22812     68/push 0/imm32/left:unused
22813     68/push 1/imm32/value:int
22814     68/push 1/imm32/is-atom?:true
22815     68/push 0x11/imm32/alloc-id:fake:payload
22816     89/<- %ecx 4/r32/esp
22817 $test-add-literal-to-mem:initialize-var1:
22818     # var var1/ecx: (payload var)
22819     68/push 0/imm32/register
22820     68/push 0/imm32/register
22821     68/push 8/imm32/stack-offset
22822     68/push 1/imm32/block-depth
22823     51/push-ecx
22824     68/push 0x11/imm32/alloc-id:fake
22825     68/push 0/imm32/name
22826     68/push 0/imm32/name
22827     68/push 0x11/imm32/alloc-id:fake:payload
22828     89/<- %ecx 4/r32/esp
22829 $test-add-literal-to-mem:initialize-var1-name:
22830     # var1->name = "var1"
22831     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22832     (copy-array Heap "var1" %eax)
22833 $test-add-literal-to-mem:initialize-literal-type:
22834     # var type/edx: (payload type-tree) = literal
22835     68/push 0/imm32/right:null
22836     68/push 0/imm32/right:null
22837     68/push 0/imm32/left:unused
22838     68/push 0/imm32/value:literal
22839     68/push 1/imm32/is-atom?:true
22840     68/push 0x11/imm32/alloc-id:fake:payload
22841     89/<- %edx 4/r32/esp
22842 $test-add-literal-to-mem:initialize-literal:
22843     # var l/edx: (payload var)
22844     68/push 0/imm32/register
22845     68/push 0/imm32/register
22846     68/push 0/imm32/no-stack-offset
22847     68/push 1/imm32/block-depth
22848     52/push-edx
22849     68/push 0x11/imm32/alloc-id:fake
22850     68/push 0/imm32/name
22851     68/push 0/imm32/name
22852     68/push 0x11/imm32/alloc-id:fake:payload
22853     89/<- %edx 4/r32/esp
22854 $test-add-literal-to-mem:initialize-literal-value:
22855     # l->name = "0x34"
22856     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
22857     (copy-array Heap "0x34" %eax)
22858 $test-add-literal-to-mem:initialize-inouts:
22859     # var inouts/esi: (payload stmt-var) = [l]
22860     68/push 0/imm32/is-deref:false
22861     68/push 0/imm32/next
22862     68/push 0/imm32/next
22863     52/push-edx/l
22864     68/push 0x11/imm32/alloc-id:fake
22865     68/push 0x11/imm32/alloc-id:fake:payload
22866     89/<- %esi 4/r32/esp
22867     # var inouts = (handle stmt-var) = [var1, var2]
22868     68/push 0/imm32/is-deref:false
22869     56/push-esi/next
22870     68/push 0x11/imm32/alloc-id:fake
22871     51/push-ecx/var1
22872     68/push 0x11/imm32/alloc-id:fake
22873     68/push 0x11/imm32/alloc-id:fake:payload
22874     89/<- %esi 4/r32/esp
22875 $test-add-literal-to-mem:initialize-stmt:
22876     # var stmt/esi: (addr statement)
22877     68/push 0/imm32/next
22878     68/push 0/imm32/next
22879     68/push 0/imm32/outputs
22880     68/push 0/imm32/outputs
22881     56/push-esi/inouts
22882     68/push 0x11/imm32/alloc-id:fake
22883     68/push 0/imm32/operation
22884     68/push 0/imm32/operation
22885     68/push 1/imm32/tag:stmt1
22886     89/<- %esi 4/r32/esp
22887 $test-add-literal-to-mem:initialize-stmt-operation:
22888     # stmt->operation = "add-to"
22889     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22890     (copy-array Heap "add-to" %eax)
22891     # convert
22892     c7 0/subop/copy *Curr-block-depth 0/imm32
22893     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22894     (flush _test-output-buffered-file)
22895 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
22901     # check output
22902     (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem")
22903     # . epilogue
22904     89/<- %esp 5/r32/ebp
22905     5d/pop-to-ebp
22906     c3/return
22907 
22908 test-shift-reg-by-literal:
22909     #   var1/ecx <- shift-left 2
22910     # =>
22911     #   c1/shift 4/subop/left %ecx 2/imm8
22912     #
22913     # . prologue
22914     55/push-ebp
22915     89/<- %ebp 4/r32/esp
22916     # setup
22917     (clear-stream _test-output-stream)
22918     (clear-stream $_test-output-buffered-file->buffer)
22919 $test-shift-reg-by-literal:initialize-var-type:
22920     # var type/ecx: (payload type-tree) = int
22921     68/push 0/imm32/right:null
22922     68/push 0/imm32/right:null
22923     68/push 0/imm32/left:unused
22924     68/push 1/imm32/value:int
22925     68/push 1/imm32/is-atom?:true
22926     68/push 0x11/imm32/alloc-id:fake:payload
22927     89/<- %ecx 4/r32/esp
22928 $test-shift-reg-by-literal:initialize-var:
22929     # var v/ecx: (payload var)
22930     68/push 0/imm32/register
22931     68/push 0/imm32/register
22932     68/push 0/imm32/no-stack-offset
22933     68/push 1/imm32/block-depth
22934     51/push-ecx
22935     68/push 0x11/imm32/alloc-id:fake
22936     68/push 0/imm32/name
22937     68/push 0/imm32/name
22938     68/push 0x11/imm32/alloc-id:fake:payload
22939     89/<- %ecx 4/r32/esp
22940 $test-shift-reg-by-literal:initialize-var-name:
22941     # v->name = "v"
22942     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22943     (copy-array Heap "v" %eax)
22944 $test-shift-reg-by-literal:initialize-var-register:
22945     # v->register = "ecx"
22946     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
22947     (copy-array Heap "ecx" %eax)
22948 $test-shift-reg-by-literal:initialize-literal-type:
22949     # var type/edx: (payload type-tree) = literal
22950     68/push 0/imm32/right:null
22951     68/push 0/imm32/right:null
22952     68/push 0/imm32/left:unused
22953     68/push 0/imm32/value:literal
22954     68/push 1/imm32/is-atom?:true
22955     68/push 0x11/imm32/alloc-id:fake:payload
22956     89/<- %edx 4/r32/esp
22957 $test-shift-reg-by-literal:initialize-literal:
22958     # var l/edx: (payload var)
22959     68/push 0/imm32/register
22960     68/push 0/imm32/register
22961     68/push 0/imm32/no-stack-offset
22962     68/push 1/imm32/block-depth
22963     52/push-edx
22964     68/push 0x11/imm32/alloc-id:fake
22965     68/push 0/imm32/name
22966     68/push 0/imm32/name
22967     68/push 0x11/imm32/alloc-id:fake:payload
22968     89/<- %edx 4/r32/esp
22969 $test-shift-reg-by-literal:initialize-literal-value:
22970     # l->name = "2"
22971     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
22972     (copy-array Heap "2" %eax)
22973 $test-shift-reg-by-literal:initialize-inouts:
22974     # var inouts/esi: (payload stmt-var) = [l]
22975     68/push 0/imm32/is-deref:false
22976     68/push 0/imm32/next
22977     68/push 0/imm32/next
22978     52/push-edx/l
22979     68/push 0x11/imm32/alloc-id:fake
22980     68/push 0x11/imm32/alloc-id:fake:payload
22981     89/<- %esi 4/r32/esp
22982 $test-shift-reg-by-literal:initialize-outputs:
22983     # var outputs/edi: (payload stmt-var) = [v]
22984     68/push 0/imm32/is-deref:false
22985     68/push 0/imm32/next
22986     68/push 0/imm32/next
22987     51/push-ecx/v
22988     68/push 0x11/imm32/alloc-id:fake
22989     68/push 0x11/imm32/alloc-id:fake:payload
22990     89/<- %edi 4/r32/esp
22991 $test-shift-reg-by-literal:initialize-stmt:
22992     # var stmt/esi: (addr statement)
22993     68/push 0/imm32/next
22994     68/push 0/imm32/next
22995     57/push-edi/outputs
22996     68/push 0x11/imm32/alloc-id:fake
22997     56/push-esi/inouts
22998     68/push 0x11/imm32/alloc-id:fake
22999     68/push 0/imm32/operation
23000     68/push 0/imm32/operation
23001     68/push 1/imm32/tag:stmt1
23002     89/<- %esi 4/r32/esp
23003 $test-shift-reg-by-literal:initialize-stmt-operation:
23004     # stmt->operation = "shift-left"
23005     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23006     (copy-array Heap "shift-left" %eax)
23007     # convert
23008     c7 0/subop/copy *Curr-block-depth 0/imm32
23009     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
23010     (flush _test-output-buffered-file)
23011 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
23017     # check output
23018     (check-next-stream-line-equal _test-output-stream "c1/shift 4/subop/left %ecx 2/imm8" "F - test-shift-reg-by-literal")
23019     # . epilogue
23020     89/<- %esp 5/r32/ebp
23021     5d/pop-to-ebp
23022     c3/return
23023 
23024 test-shift-mem-by-literal:
23025     #   shift-left var 3
23026     # =>
23027     #   c1/shift 4/subop/left *(ebp+8) 3/imm8
23028     #
23029     # . prologue
23030     55/push-ebp
23031     89/<- %ebp 4/r32/esp
23032     # setup
23033     (clear-stream _test-output-stream)
23034     (clear-stream $_test-output-buffered-file->buffer)
23035 $test-shift-mem-by-literal:initialize-type:
23036     # var type/ecx: (payload type-tree) = int
23037     68/push 0/imm32/right:null
23038     68/push 0/imm32/right:null
23039     68/push 0/imm32/left:unused
23040     68/push 1/imm32/value:int
23041     68/push 1/imm32/is-atom?:true
23042     68/push 0x11/imm32/alloc-id:fake:payload
23043     89/<- %ecx 4/r32/esp
23044 $test-shift-mem-by-literal:initialize-var1:
23045     # var var1/ecx: (payload var)
23046     68/push 0/imm32/register
23047     68/push 0/imm32/register
23048     68/push 8/imm32/stack-offset
23049     68/push 1/imm32/block-depth
23050     51/push-ecx
23051     68/push 0x11/imm32/alloc-id:fake
23052     68/push 0/imm32/name
23053     68/push 0/imm32/name
23054     68/push 0x11/imm32/alloc-id:fake:payload
23055     89/<- %ecx 4/r32/esp
23056 $test-shift-mem-by-literal:initialize-var1-name:
23057     # var1->name = "var1"
23058     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23059     (copy-array Heap "var1" %eax)
23060 $test-shift-mem-by-literal:initialize-literal-type:
23061     # var type/edx: (payload type-tree) = literal
23062     68/push 0/imm32/right:null
23063     68/push 0/imm32/right:null
23064     68/push 0/imm32/left:unused
23065     68/push 0/imm32/value:literal
23066     68/push 1/imm32/is-atom?:true
23067     68/push 0x11/imm32/alloc-id:fake:payload
23068     89/<- %edx 4/r32/esp
23069 $test-shift-mem-by-literal:initialize-literal:
23070     # var l/edx: (payload var)
23071     68/push 0/imm32/register
23072     68/push 0/imm32/register
23073     68/push 0/imm32/no-stack-offset
23074     68/push 1/imm32/block-depth
23075     52/push-edx
23076     68/push 0x11/imm32/alloc-id:fake
23077     68/push 0/imm32/name
23078     68/push 0/imm32/name
23079     68/push 0x11/imm32/alloc-id:fake:payload
23080     89/<- %edx 4/r32/esp
23081 $test-shift-mem-by-literal:initialize-literal-value:
23082     # l->name = "3"
23083     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
23084     (copy-array Heap "3" %eax)
23085 $test-shift-mem-by-literal:initialize-inouts:
23086     # var inouts/esi: (payload stmt-var) = [l]
23087     68/push 0/imm32/is-deref:false
23088     68/push 0/imm32/next
23089     68/push 0/imm32/next
23090     52/push-edx/l
23091     68/push 0x11/imm32/alloc-id:fake
23092     68/push 0x11/imm32/alloc-id:fake:payload
23093     89/<- %esi 4/r32/esp
23094     # var inouts = (handle stmt-var) = [var1, var2]
23095     68/push 0/imm32/is-deref:false
23096     56/push-esi/next
23097     68/push 0x11/imm32/alloc-id:fake
23098     51/push-ecx/var1
23099     68/push 0x11/imm32/alloc-id:fake
23100     68/push 0x11/imm32/alloc-id:fake:payload
23101     89/<- %esi 4/r32/esp
23102 $test-shift-mem-by-literal:initialize-stmt:
23103     # var stmt/esi: (addr statement)
23104     68/push 0/imm32/next
23105     68/push 0/imm32/next
23106     68/push 0/imm32/outputs
23107     68/push 0/imm32/outputs
23108     56/push-esi/inouts
23109     68/push 0x11/imm32/alloc-id:fake
23110     68/push 0/imm32/operation
23111     68/push 0/imm32/operation
23112     68/push 1/imm32/tag:stmt1
23113     89/<- %esi 4/r32/esp
23114 $test-shift-mem-by-literal:initialize-stmt-operation:
23115     # stmt->operation = "shift-left"
23116     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23117     (copy-array Heap "shift-left" %eax)
23118     # convert
23119     c7 0/subop/copy *Curr-block-depth 0/imm32
23120     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
23121     (flush _test-output-buffered-file)
23122 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
23128     # check output
23129     (check-next-stream-line-equal _test-output-stream "c1/shift 4/subop/left *(ebp+0x00000008) 3/imm8" "F - test-shift-mem-by-literal")
23130     # . epilogue
23131     89/<- %esp 5/r32/ebp
23132     5d/pop-to-ebp
23133     c3/return
23134 
23135 test-compare-reg-with-reg:
23136     #   compare var1/ecx, var2/eax
23137     # =>
23138     #   39/compare %ecx 0/r32/eax
23139     #
23140     # . prologue
23141     55/push-ebp
23142     89/<- %ebp 4/r32/esp
23143     # setup
23144     (clear-stream _test-output-stream)
23145     (clear-stream $_test-output-buffered-file->buffer)
23146 $test-compare-reg-with-reg:initialize-type:
23147     # var type/ecx: (payload type-tree) = int
23148     68/push 0/imm32/right:null
23149     68/push 0/imm32/right:null
23150     68/push 0/imm32/left:unused
23151     68/push 1/imm32/value:int
23152     68/push 1/imm32/is-atom?:true
23153     68/push 0x11/imm32/alloc-id:fake:payload
23154     89/<- %ecx 4/r32/esp
23155 $test-compare-reg-with-reg:initialize-var1:
23156     # var var1/ecx: (payload var)
23157     68/push 0/imm32/register
23158     68/push 0/imm32/register
23159     68/push 0/imm32/no-stack-offset
23160     68/push 1/imm32/block-depth
23161     51/push-ecx
23162     68/push 0x11/imm32/alloc-id:fake
23163     68/push 0/imm32/name
23164     68/push 0/imm32/name
23165     68/push 0x11/imm32/alloc-id:fake:payload
23166     89/<- %ecx 4/r32/esp
23167 $test-compare-reg-with-reg:initialize-var1-name:
23168     # var1->name = "var1"
23169     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23170     (copy-array Heap "var1" %eax)
23171 $test-compare-reg-with-reg:initialize-var1-register:
23172     # var1->register = "ecx"
23173     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
23174     (copy-array Heap "ecx" %eax)
23175 $test-compare-reg-with-reg:initialize-var2:
23176     # var var2/edx: (payload var)
23177     68/push 0/imm32/register
23178     68/push 0/imm32/register
23179     68/push 0/imm32/no-stack-offset
23180     68/push 1/imm32/block-depth
23181     ff 6/subop/push *(ecx+0x10)
23182     68/push 0x11/imm32/alloc-id:fake
23183     68/push 0/imm32/name
23184     68/push 0/imm32/name
23185     68/push 0x11/imm32/alloc-id:fake:payload
23186     89/<- %edx 4/r32/esp
23187 $test-compare-reg-with-reg:initialize-var2-name:
23188     # var2->name = "var2"
23189     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
23190     (copy-array Heap "var2" %eax)
23191 $test-compare-reg-with-reg:initialize-var2-register:
23192     # var2->register = "eax"
23193     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
23194     (copy-array Heap "eax" %eax)
23195 $test-compare-reg-with-reg:initialize-inouts:
23196     # var inouts/esi: (payload stmt-var) = [var2]
23197     68/push 0/imm32/is-deref:false
23198     68/push 0/imm32/next
23199     68/push 0/imm32/next
23200     52/push-edx/var2
23201     68/push 0x11/imm32/alloc-id:fake
23202     68/push 0x11/imm32/alloc-id:fake:payload
23203     89/<- %esi 4/r32/esp
23204     # inouts = [var1, var2]
23205     68/push 0/imm32/is-deref:false
23206     56/push-esi/next
23207     68/push 0x11/imm32/alloc-id:fake
23208     51/push-ecx/var1
23209     68/push 0x11/imm32/alloc-id:fake
23210     68/push 0x11/imm32/alloc-id:fake:payload
23211     89/<- %esi 4/r32/esp
23212 $test-compare-reg-with-reg:initialize-stmt:
23213     # var stmt/esi: (addr statement)
23214     68/push 0/imm32/next
23215     68/push 0/imm32/next
23216     68/push 0/imm32/outputs
23217     68/push 0/imm32/outputs
23218     56/push-esi/inouts
23219     68/push 0x11/imm32/alloc-id:fake
23220     68/push 0/imm32/operation
23221     68/push 0/imm32/operation
23222     68/push 1/imm32/tag:stmt1
23223     89/<- %esi 4/r32/esp
23224 $test-compare-reg-with-reg:initialize-stmt-operation:
23225     # stmt->operation = "compare"
23226     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23227     (copy-array Heap "compare" %eax)
23228     # convert
23229     c7 0/subop/copy *Curr-block-depth 0/imm32
23230     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
23231     (flush _test-output-buffered-file)
23232 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
23238     # check output
23239     (check-next-stream-line-equal _test-output-stream "39/compare-> %ecx 0x00000000/r32" "F - test-compare-reg-with-reg")
23240     # . epilogue
23241     89/<- %esp 5/r32/ebp
23242     5d/pop-to-ebp
23243     c3/return
23244 
23245 test-compare-mem-with-reg:
23246     #   compare var1, var2/eax
23247     # =>
23248     #   39/compare *(ebp+___) 0/r32/eax
23249     #
23250     # . prologue
23251     55/push-ebp
23252     89/<- %ebp 4/r32/esp
23253     # setup
23254     (clear-stream _test-output-stream)
23255     (clear-stream $_test-output-buffered-file->buffer)
23256 $test-compare-mem-with-reg:initialize-type:
23257     # var type/ecx: (payload type-tree) = int
23258     68/push 0/imm32/right:null
23259     68/push 0/imm32/right:null
23260     68/push 0/imm32/left:unused
23261     68/push 1/imm32/value:int
23262     68/push 1/imm32/is-atom?:true
23263     68/push 0x11/imm32/alloc-id:fake:payload
23264     89/<- %ecx 4/r32/esp
23265 $test-compare-mem-with-reg:initialize-var1:
23266     # var var1/ecx: (payload var)
23267     68/push 0/imm32/register
23268     68/push 0/imm32/register
23269     68/push 8/imm32/stack-offset
23270     68/push 1/imm32/block-depth
23271     51/push-ecx
23272     68/push 0x11/imm32/alloc-id:fake
23273     68/push 0/imm32/name
23274     68/push 0/imm32/name
23275     68/push 0x11/imm32/alloc-id:fake:payload
23276     89/<- %ecx 4/r32/esp
23277 $test-compare-mem-with-reg:initialize-var1-name:
23278     # var1->name = "var1"
23279     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23280     (copy-array Heap "var1" %eax)
23281 $test-compare-mem-with-reg:initialize-var2:
23282     # var var2/edx: (payload var)
23283     68/push 0/imm32/register
23284     68/push 0/imm32/register
23285     68/push 0/imm32/no-stack-offset
23286     68/push 1/imm32/block-depth
23287     ff 6/subop/push *(ecx+0x10)
23288     68/push 0x11/imm32/alloc-id:fake
23289     68/push 0/imm32/name
23290     68/push 0/imm32/name
23291     68/push 0x11/imm32/alloc-id:fake:payload
23292     89/<- %edx 4/r32/esp
23293 $test-compare-mem-with-reg:initialize-var2-name:
23294     # var2->name = "var2"
23295     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
23296     (copy-array Heap "var2" %eax)
23297 $test-compare-mem-with-reg:initialize-var2-register:
23298     # var2->register = "eax"
23299     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
23300     (copy-array Heap "eax" %eax)
23301 $test-compare-mem-with-reg:initialize-inouts:
23302     # var inouts/esi: (payload stmt-var) = [var2]
23303     68/push 0/imm32/is-deref:false
23304     68/push 0/imm32/next
23305     68/push 0/imm32/next
23306     52/push-edx/var2
23307     68/push 0x11/imm32/alloc-id:fake
23308     68/push 0x11/imm32/alloc-id:fake:payload
23309     89/<- %esi 4/r32/esp
23310     # inouts = [var1, var2]
23311     68/push 0/imm32/is-deref:false
23312     56/push-esi/next
23313     68/push 0x11/imm32/alloc-id:fake
23314     51/push-ecx/var1
23315     68/push 0x11/imm32/alloc-id:fake
23316     68/push 0x11/imm32/alloc-id:fake:payload
23317     89/<- %esi 4/r32/esp
23318 $test-compare-mem-with-reg:initialize-stmt:
23319     # var stmt/esi: (addr statement)
23320     68/push 0/imm32/next
23321     68/push 0/imm32/next
23322     68/push 0/imm32/outputs
23323     68/push 0/imm32/outputs
23324     56/push-esi/inouts
23325     68/push 0x11/imm32/alloc-id:fake
23326     68/push 0/imm32/operation
23327     68/push 0/imm32/operation
23328     68/push 1/imm32/tag:stmt1
23329     89/<- %esi 4/r32/esp
23330 $test-compare-mem-with-reg:initialize-stmt-operation:
23331     # stmt->operation = "compare"
23332     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23333     (copy-array Heap "compare" %eax)
23334     # convert
23335     c7 0/subop/copy *Curr-block-depth 0/imm32
23336     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
23337     (flush _test-output-buffered-file)
23338 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
23344     # check output
23345     (check-next-stream-line-equal _test-output-stream "39/compare-> *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-mem-with-reg")
23346     # . epilogue
23347     89/<- %esp 5/r32/ebp
23348     5d/pop-to-ebp
23349     c3/return
23350 
23351 test-compare-reg-with-mem:
23352     #   compare var1/eax, var2
23353     # =>
23354     #   3b/compare<- *(ebp+___) 0/r32/eax
23355     #
23356     # . prologue
23357     55/push-ebp
23358     89/<- %ebp 4/r32/esp
23359     # setup
23360     (clear-stream _test-output-stream)
23361     (clear-stream $_test-output-buffered-file->buffer)
23362 $test-compare-reg-with-mem:initialize-type:
23363     # var type/ecx: (payload type-tree) = int
23364     68/push 0/imm32/right:null
23365     68/push 0/imm32/right:null
23366     68/push 0/imm32/left:unused
23367     68/push 1/imm32/value:int
23368     68/push 1/imm32/is-atom?:true
23369     68/push 0x11/imm32/alloc-id:fake:payload
23370     89/<- %ecx 4/r32/esp
23371 $test-compare-reg-with-mem:initialize-var1:
23372     # var var1/ecx: (payload var)
23373     68/push 0/imm32/register
23374     68/push 0/imm32/register
23375     68/push 0/imm32/no-stack-offset
23376     68/push 1/imm32/block-depth
23377     51/push-ecx
23378     68/push 0x11/imm32/alloc-id:fake
23379     68/push 0/imm32/name
23380     68/push 0/imm32/name
23381     68/push 0x11/imm32/alloc-id:fake:payload
23382     89/<- %ecx 4/r32/esp
23383 $test-compare-reg-with-mem:initialize-var1-name:
23384     # var1->name = "var1"
23385     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23386     (copy-array Heap "var1" %eax)
23387 $test-compare-reg-with-mem:initialize-var1-register:
23388     # var1->register = "eax"
23389     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
23390     (copy-array Heap "eax" %eax)
23391 $test-compare-reg-with-mem:initialize-var2:
23392     # var var2/edx: (payload var)
23393     68/push 0/imm32/register
23394     68/push 0/imm32/register
23395     68/push 8/imm32/stack-offset
23396     68/push 1/imm32/block-depth
23397     ff 6/subop/push *(ecx+0x10)
23398     68/push 0x11/imm32/alloc-id:fake
23399     68/push 0/imm32/name
23400     68/push 0/imm32/name
23401     68/push 0x11/imm32/alloc-id:fake:payload
23402     89/<- %edx 4/r32/esp
23403 $test-compare-reg-with-mem:initialize-var2-name:
23404     # var2->name = "var2"
23405     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
23406     (copy-array Heap "var2" %eax)
23407 $test-compare-reg-with-mem:initialize-inouts:
23408     # var inouts/esi: (payload stmt-var) = [var2]
23409     68/push 0/imm32/is-deref:false
23410     68/push 0/imm32/next
23411     68/push 0/imm32/next
23412     52/push-edx/var2
23413     68/push 0x11/imm32/alloc-id:fake
23414     68/push 0x11/imm32/alloc-id:fake:payload
23415     89/<- %esi 4/r32/esp
23416     # inouts = [var1, var2]
23417     68/push 0/imm32/is-deref:false
23418     56/push-esi/next
23419     68/push 0x11/imm32/alloc-id:fake
23420     51/push-ecx/var1
23421     68/push 0x11/imm32/alloc-id:fake
23422     68/push 0x11/imm32/alloc-id:fake:payload
23423     89/<- %esi 4/r32/esp
23424 $test-compare-reg-with-mem:initialize-stmt:
23425     # var stmt/esi: (addr statement)
23426     68/push 0/imm32/next
23427     68/push 0/imm32/next
23428     68/push 0/imm32/outputs
23429     68/push 0/imm32/outputs
23430     56/push-esi/inouts
23431     68/push 0x11/imm32/alloc-id:fake
23432     68/push 0/imm32/operation
23433     68/push 0/imm32/operation
23434     68/push 1/imm32/tag:stmt1
23435     89/<- %esi 4/r32/esp
23436 $test-compare-reg-with-mem:initialize-stmt-operation:
23437     # stmt->operation = "compare"
23438     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23439     (copy-array Heap "compare" %eax)
23440     # convert
23441     c7 0/subop/copy *Curr-block-depth 0/imm32
23442     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
23443     (flush _test-output-buffered-file)
23444 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
23450     # check output
23451     (check-next-stream-line-equal _test-output-stream "3b/compare<- *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-reg-with-mem")
23452     # . epilogue
23453     89/<- %esp 5/r32/ebp
23454     5d/pop-to-ebp
23455     c3/return
23456 
23457 test-compare-mem-with-literal:
23458     #   compare var1, 0x34
23459     # =>
23460     #   81 7/subop/compare *(ebp+___) 0x34/imm32
23461     #
23462     # . prologue
23463     55/push-ebp
23464     89/<- %ebp 4/r32/esp
23465     # setup
23466     (clear-stream _test-output-stream)
23467     (clear-stream $_test-output-buffered-file->buffer)
23468 $test-compare-mem-with-literal:initialize-type:
23469     # var type/ecx: (payload type-tree) = int
23470     68/push 0/imm32/right:null
23471     68/push 0/imm32/right:null
23472     68/push 0/imm32/left:unused
23473     68/push 1/imm32/value:int
23474     68/push 1/imm32/is-atom?:true
23475     68/push 0x11/imm32/alloc-id:fake:payload
23476     89/<- %ecx 4/r32/esp
23477 $test-compare-mem-with-literal:initialize-var1:
23478     # var var1/ecx: (payload var)
23479     68/push 0/imm32/register
23480     68/push 0/imm32/register
23481     68/push 8/imm32/stack-offset
23482     68/push 1/imm32/block-depth
23483     51/push-ecx
23484     68/push 0x11/imm32/alloc-id:fake
23485     68/push 0/imm32/name
23486     68/push 0/imm32/name
23487     68/push 0x11/imm32/alloc-id:fake:payload
23488     89/<- %ecx 4/r32/esp
23489 $test-compare-mem-with-literal:initialize-var1-name:
23490     # var1->name = "var1"
23491     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23492     (copy-array Heap "var1" %eax)
23493 $test-compare-mem-with-literal:initialize-literal-type:
23494     # var type/edx: (payload type-tree) = literal
23495     68/push 0/imm32/right:null
23496     68/push 0/imm32/right:null
23497     68/push 0/imm32/left:unused
23498     68/push 0/imm32/value:literal
23499     68/push 1/imm32/is-atom?:true
23500     68/push 0x11/imm32/alloc-id:fake:payload
23501     89/<- %edx 4/r32/esp
23502 $test-compare-mem-with-literal:initialize-literal:
23503     # var l/edx: (payload var)
23504     68/push 0/imm32/register
23505     68/push 0/imm32/register
23506     68/push 0/imm32/no-stack-offset
23507     68/push 1/imm32/block-depth
23508     52/push-edx
23509     68/push 0x11/imm32/alloc-id:fake
23510     68/push 0/imm32/name
23511     68/push 0/imm32/name
23512     68/push 0x11/imm32/alloc-id:fake:payload
23513     89/<- %edx 4/r32/esp
23514 $test-compare-mem-with-literal:initialize-literal-value:
23515     # l->name = "0x34"
23516     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
23517     (copy-array Heap "0x34" %eax)
23518 $test-compare-mem-with-literal:initialize-inouts:
23519     # var inouts/esi: (payload stmt-var) = [l]
23520     68/push 0/imm32/is-deref:false
23521     68/push 0/imm32/next
23522     68/push 0/imm32/next
23523     52/push-edx/l
23524     68/push 0x11/imm32/alloc-id:fake
23525     68/push 0x11/imm32/alloc-id:fake:payload
23526     89/<- %esi 4/r32/esp
23527     # var inouts = (handle stmt-var) = [var1, var2]
23528     68/push 0/imm32/is-deref:false
23529     56/push-esi/next
23530     68/push 0x11/imm32/alloc-id:fake
23531     51/push-ecx/var1
23532     68/push 0x11/imm32/alloc-id:fake
23533     68/push 0x11/imm32/alloc-id:fake:payload
23534     89/<- %esi 4/r32/esp
23535 $test-compare-mem-with-literal:initialize-stmt:
23536     # var stmt/esi: (addr statement)
23537     68/push 0/imm32/next
23538     68/push 0/imm32/next
23539     68/push 0/imm32/outputs
23540     68/push 0/imm32/outputs
23541     56/push-esi/inouts
23542     68/push 0x11/imm32/alloc-id:fake
23543     68/push 0/imm32/operation
23544     68/push 0/imm32/operation
23545     68/push 1/imm32/tag:stmt1
23546     89/<- %esi 4/r32/esp
23547 $test-compare-mem-with-literal:initialize-stmt-operation:
23548     # stmt->operation = "compare"
23549     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23550     (copy-array Heap "compare" %eax)
23551     # convert
23552     c7 0/subop/copy *Curr-block-depth 0/imm32
23553     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
23554     (flush _test-output-buffered-file)
23555 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
23561     # check output
23562     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare *(ebp+0x00000008) 0x34/imm32" "F - test-compare-mem-with-literal")
23563     # . epilogue
23564     89/<- %esp 5/r32/ebp
23565     5d/pop-to-ebp
23566     c3/return
23567 
23568 test-compare-eax-with-literal:
23569     #   compare var1/eax 0x34
23570     # =>
23571     #   3d/compare-eax-with 0x34/imm32
23572     #
23573     # . prologue
23574     55/push-ebp
23575     89/<- %ebp 4/r32/esp
23576     # setup
23577     (clear-stream _test-output-stream)
23578     (clear-stream $_test-output-buffered-file->buffer)
23579 $test-compare-eax-with-literal:initialize-type:
23580     # var type/ecx: (payload type-tree) = int
23581     68/push 0/imm32/right:null
23582     68/push 0/imm32/right:null
23583     68/push 0/imm32/left:unused
23584     68/push 1/imm32/value:int
23585     68/push 1/imm32/is-atom?:true
23586     68/push 0x11/imm32/alloc-id:fake:payload
23587     89/<- %ecx 4/r32/esp
23588 $test-compare-eax-with-literal:initialize-var1:
23589     # var var1/ecx: (payload var)
23590     68/push 0/imm32/register
23591     68/push 0/imm32/register
23592     68/push 0/imm32/no-stack-offset
23593     68/push 1/imm32/block-depth
23594     51/push-ecx
23595     68/push 0x11/imm32/alloc-id:fake
23596     68/push 0/imm32/name
23597     68/push 0/imm32/name
23598     68/push 0x11/imm32/alloc-id:fake:payload
23599     89/<- %ecx 4/r32/esp
23600 $test-compare-eax-with-literal:initialize-var1-name:
23601     # var1->name = "var1"
23602     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23603     (copy-array Heap "var1" %eax)
23604 $test-compare-eax-with-literal:initialize-var1-register:
23605     # v->register = "eax"
23606     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
23607     (copy-array Heap "eax" %eax)
23608 $test-compare-eax-with-literal:initialize-literal-type:
23609     # var type/edx: (payload type-tree) = literal
23610     68/push 0/imm32/right:null
23611     68/push 0/imm32/right:null
23612     68/push 0/imm32/left:unused
23613     68/push 0/imm32/value:literal
23614     68/push 1/imm32/is-atom?:true
23615     68/push 0x11/imm32/alloc-id:fake:payload
23616     89/<- %edx 4/r32/esp
23617 $test-compare-eax-with-literal:initialize-literal:
23618     # var l/edx: (payload var)
23619     68/push 0/imm32/register
23620     68/push 0/imm32/register
23621     68/push 0/imm32/no-stack-offset
23622     68/push 1/imm32/block-depth
23623     52/push-edx
23624     68/push 0x11/imm32/alloc-id:fake
23625     68/push 0/imm32/name
23626     68/push 0/imm32/name
23627     68/push 0x11/imm32/alloc-id:fake:payload
23628     89/<- %edx 4/r32/esp
23629 $test-compare-eax-with-literal:initialize-literal-value:
23630     # l->name = "0x34"
23631     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
23632     (copy-array Heap "0x34" %eax)
23633 $test-compare-eax-with-literal:initialize-inouts:
23634     # var inouts/esi: (payload stmt-var) = [l]
23635     68/push 0/imm32/is-deref:false
23636     68/push 0/imm32/next
23637     68/push 0/imm32/next
23638     52/push-edx/l
23639     68/push 0x11/imm32/alloc-id:fake
23640     68/push 0x11/imm32/alloc-id:fake:payload
23641     89/<- %esi 4/r32/esp
23642     # var inouts = (handle stmt-var) = [var1, var2]
23643     68/push 0/imm32/is-deref:false
23644     56/push-esi/next
23645     68/push 0x11/imm32/alloc-id:fake
23646     51/push-ecx/var1
23647     68/push 0x11/imm32/alloc-id:fake
23648     68/push 0x11/imm32/alloc-id:fake:payload
23649     89/<- %esi 4/r32/esp
23650 $test-compare-eax-with-literal:initialize-stmt:
23651     # var stmt/esi: (addr statement)
23652     68/push 0/imm32/next
23653     68/push 0/imm32/next
23654     68/push 0/imm32/outputs
23655     68/push 0/imm32/outputs
23656     56/push-esi/inouts
23657     68/push 0x11/imm32/alloc-id:fake
23658     68/push 0/imm32/operation
23659     68/push 0/imm32/operation
23660     68/push 1/imm32/tag:stmt1
23661     89/<- %esi 4/r32/esp
23662 $test-compare-eax-with-literal:initialize-stmt-operation:
23663     # stmt->operation = "compare"
23664     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23665     (copy-array Heap "compare" %eax)
23666     # convert
23667     c7 0/subop/copy *Curr-block-depth 0/imm32
23668     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
23669     (flush _test-output-buffered-file)
23670 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
23676     # check output
23677     (check-next-stream-line-equal _test-output-stream "3d/compare-eax-with 0x34/imm32" "F - test-compare-eax-with-literal")
23678     # . epilogue
23679     89/<- %esp 5/r32/ebp
23680     5d/pop-to-ebp
23681     c3/return
23682 
23683 test-compare-reg-with-literal:
23684     #   compare var1/ecx 0x34
23685     # =>
23686     #   81 7/subop/compare %ecx 0x34/imm32
23687     #
23688     # . prologue
23689     55/push-ebp
23690     89/<- %ebp 4/r32/esp
23691     # setup
23692     (clear-stream _test-output-stream)
23693     (clear-stream $_test-output-buffered-file->buffer)
23694 $test-compare-reg-with-literal:initialize-type:
23695     # var type/ecx: (payload type-tree) = int
23696     68/push 0/imm32/right:null
23697     68/push 0/imm32/right:null
23698     68/push 0/imm32/left:unused
23699     68/push 1/imm32/value:int
23700     68/push 1/imm32/is-atom?:true
23701     68/push 0x11/imm32/alloc-id:fake:payload
23702     89/<- %ecx 4/r32/esp
23703 $test-compare-reg-with-literal:initialize-var1:
23704     # var var1/ecx: (payload var)
23705     68/push 0/imm32/register
23706     68/push 0/imm32/register
23707     68/push 0/imm32/no-stack-offset
23708     68/push 1/imm32/block-depth
23709     51/push-ecx
23710     68/push 0x11/imm32/alloc-id:fake
23711     68/push 0/imm32/name
23712     68/push 0/imm32/name
23713     68/push 0x11/imm32/alloc-id:fake:payload
23714     89/<- %ecx 4/r32/esp
23715 $test-compare-reg-with-literal:initialize-var1-name:
23716     # var1->name = "var1"
23717     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23718     (copy-array Heap "var1" %eax)
23719 $test-compare-reg-with-literal:initialize-var1-register:
23720     # v->register = "ecx"
23721     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
23722     (copy-array Heap "ecx" %eax)
23723 $test-compare-reg-with-literal:initialize-literal-type:
23724     # var type/edx: (payload type-tree) = literal
23725     68/push 0/imm32/right:null
23726     68/push 0/imm32/right:null
23727     68/push 0/imm32/left:unused
23728     68/push 0/imm32/value:literal
23729     68/push 1/imm32/is-atom?:true
23730     68/push 0x11/imm32/alloc-id:fake:payload
23731     89/<- %edx 4/r32/esp
23732 $test-compare-reg-with-literal:initialize-literal:
23733     # var l/edx: (payload var)
23734     68/push 0/imm32/register
23735     68/push 0/imm32/register
23736     68/push 0/imm32/no-stack-offset
23737     68/push 1/imm32/block-depth
23738     52/push-edx
23739     68/push 0x11/imm32/alloc-id:fake
23740     68/push 0/imm32/name
23741     68/push 0/imm32/name
23742     68/push 0x11/imm32/alloc-id:fake:payload
23743     89/<- %edx 4/r32/esp
23744 $test-compare-reg-with-literal:initialize-literal-value:
23745     # l->name = "0x34"
23746     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
23747     (copy-array Heap "0x34" %eax)
23748 $test-compare-reg-with-literal:initialize-inouts:
23749     # var inouts/esi: (payload stmt-var) = [l]
23750     68/push 0/imm32/is-deref:false
23751     68/push 0/imm32/next
23752     68/push 0/imm32/next
23753     52/push-edx/l
23754     68/push 0x11/imm32/alloc-id:fake
23755     68/push 0x11/imm32/alloc-id:fake:payload
23756     89/<- %esi 4/r32/esp
23757     # var inouts = (handle stmt-var) = [var1, var2]
23758     68/push 0/imm32/is-deref:false
23759     56/push-esi/next
23760     68/push 0x11/imm32/alloc-id:fake
23761     51/push-ecx/var1
23762     68/push 0x11/imm32/alloc-id:fake
23763     68/push 0x11/imm32/alloc-id:fake:payload
23764     89/<- %esi 4/r32/esp
23765 $test-compare-reg-with-literal:initialize-stmt:
23766     # var stmt/esi: (addr statement)
23767     68/push 0/imm32/next
23768     68/push 0/imm32/next
23769     68/push 0/imm32/outputs
23770     68/push 0/imm32/outputs
23771     56/push-esi/inouts
23772     68/push 0x11/imm32/alloc-id:fake
23773     68/push 0/imm32/operation
23774     68/push 0/imm32/operation
23775     68/push 1/imm32/tag:stmt1
23776     89/<- %esi 4/r32/esp
23777 $test-compare-reg-with-literal:initialize-stmt-operation:
23778     # stmt->operation = "compare"
23779     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23780     (copy-array Heap "compare" %eax)
23781     # convert
23782     c7 0/subop/copy *Curr-block-depth 0/imm32
23783     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
23784     (flush _test-output-buffered-file)
23785 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
23791     # check output
23792     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare %ecx 0x34/imm32" "F - test-compare-reg-with-literal")
23793     # . epilogue
23794     89/<- %esp 5/r32/ebp
23795     5d/pop-to-ebp
23796     c3/return
23797 
23798 test-emit-subx-stmt-function-call:
23799     # Call a function on a variable on the stack.
23800     #   f foo
23801     # =>
23802     #   (f *(ebp-8))
23803     # (Changing the function name supports overloading in general, but here it
23804     # just serves to help disambiguate things.)
23805     #
23806     # There's a variable on the var stack as follows:
23807     #   name: 'foo'
23808     #   type: int
23809     #   stack-offset: -8
23810     #
23811     # There's nothing in primitives.
23812     #
23813     # We don't perform any checking here on the type of 'f'.
23814     #
23815     # . prologue
23816     55/push-ebp
23817     89/<- %ebp 4/r32/esp
23818     # setup
23819     (clear-stream _test-output-stream)
23820     (clear-stream $_test-output-buffered-file->buffer)
23821 $test-emit-subx-function-call:initialize-type:
23822     # var type/ecx: (payload type-tree) = int
23823     68/push 0/imm32/right:null
23824     68/push 0/imm32/right:null
23825     68/push 0/imm32/left:unused
23826     68/push 1/imm32/value:int
23827     68/push 1/imm32/is-atom?:true
23828     68/push 0x11/imm32/alloc-id:fake:payload
23829     89/<- %ecx 4/r32/esp
23830 $test-emit-subx-function-call:initialize-var:
23831     # var var-foo/ecx: (payload var) = var(type)
23832     68/push 0/imm32/no-register
23833     68/push 0/imm32/no-register
23834     68/push -8/imm32/stack-offset
23835     68/push 1/imm32/block-depth
23836     51/push-ecx/type
23837     68/push 0x11/imm32/alloc-id:fake
23838     68/push 0/imm32/name
23839     68/push 0/imm32/name
23840     68/push 0x11/imm32/alloc-id:fake:payload
23841     89/<- %ecx 4/r32/esp
23842 $test-emit-subx-function-call:initialize-var-name:
23843     # var-foo->name = "foo"
23844     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23845     (copy-array Heap "foo" %eax)
23846 $test-emit-subx-function-call:initialize-stmt-var:
23847     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
23848     68/push 0/imm32/is-deref:false
23849     68/push 0/imm32/next
23850     68/push 0/imm32/next
23851     51/push-ecx/var-foo
23852     68/push 0x11/imm32/alloc-id:fake
23853     68/push 0x11/imm32/alloc-id:fake:payload
23854     89/<- %ebx 4/r32/esp
23855 $test-emit-subx-function-call:initialize-stmt:
23856     # var stmt/esi: (addr statement)
23857     68/push 0/imm32/no-outputs
23858     68/push 0/imm32/no-outputs
23859     53/push-ebx/inouts
23860     68/push 0x11/imm32/alloc-id:fake
23861     68/push 0/imm32/operation
23862     68/push 0/imm32/operation
23863     68/push 1/imm32/tag
23864     89/<- %esi 4/r32/esp
23865 $test-emit-subx-function-call:initialize-stmt-operation:
23866     # stmt->operation = "f"
23867     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23868     (copy-array Heap "f" %eax)
23869     # convert
23870     c7 0/subop/copy *Curr-block-depth 0/imm32
23871     (emit-subx-stmt _test-output-buffered-file %esi 0 Stderr 0)
23872     (flush _test-output-buffered-file)
23873 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
23879     # check output
23880     (check-next-stream-line-equal _test-output-stream "(f *(ebp+0xfffffff8))" "F - test-emit-subx-stmt-function-call")
23881     # . epilogue
23882     89/<- %esp 5/r32/ebp
23883     5d/pop-to-ebp
23884     c3/return
23885 
23886 test-emit-subx-stmt-function-call-with-literal-arg:
23887     # Call a function on a literal.
23888     #   f 0x34
23889     # =>
23890     #   (f2 0x34)
23891     #
23892     # . prologue
23893     55/push-ebp
23894     89/<- %ebp 4/r32/esp
23895     # setup
23896     (clear-stream _test-output-stream)
23897     (clear-stream $_test-output-buffered-file->buffer)
23898 $test-emit-subx-function-call-with-literal-arg:initialize-type:
23899     # var type/ecx: (payload type-tree) = int
23900     68/push 0/imm32/right:null
23901     68/push 0/imm32/right:null
23902     68/push 0/imm32/left:unused
23903     68/push 0/imm32/value:literal
23904     68/push 1/imm32/is-atom?:true
23905     68/push 0x11/imm32/alloc-id:fake:payload
23906     89/<- %ecx 4/r32/esp
23907 $test-emit-subx-function-call-with-literal-arg:initialize-var:
23908     # var var-foo/ecx: (payload var) = var(lit)
23909     68/push 0/imm32/no-register
23910     68/push 0/imm32/no-register
23911     68/push 0/imm32/no-stack-offset
23912     68/push 1/imm32/block-depth
23913     51/push-ecx/type
23914     68/push 0x11/imm32/alloc-id:fake
23915     68/push 0/imm32/name
23916     68/push 0/imm32/name
23917     68/push 0x11/imm32/alloc-id:fake:payload
23918     89/<- %ecx 4/r32/esp
23919 $test-emit-subx-function-call-with-literal-arg:initialize-var-name:
23920     # var-foo->name = "0x34"
23921     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23922     (copy-array Heap "0x34" %eax)
23923 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-var:
23924     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
23925     68/push 0/imm32/is-deref:false
23926     68/push 0/imm32/next
23927     68/push 0/imm32/next
23928     51/push-ecx/var-foo
23929     68/push 0x11/imm32/alloc-id:fake
23930     68/push 0x11/imm32/alloc-id:fake:payload
23931     89/<- %ebx 4/r32/esp
23932 $test-emit-subx-function-call-with-literal-arg:initialize-stmt:
23933     # var stmt/esi: (addr statement)
23934     68/push 0/imm32/no-outputs
23935     68/push 0/imm32/no-outputs
23936     53/push-ebx/inouts
23937     68/push 0x11/imm32/alloc-id:fake
23938     68/push 0/imm32/operation
23939     68/push 0/imm32/operation
23940     68/push 1/imm32/tag
23941     89/<- %esi 4/r32/esp
23942 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-operation:
23943     # stmt->operation = "f"
23944     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23945     (copy-array Heap "f" %eax)
23946     # convert
23947     c7 0/subop/copy *Curr-block-depth 0/imm32
23948     (emit-subx-stmt _test-output-buffered-file %esi 0 %ebx Stderr 0)
23949     (flush _test-output-buffered-file)
23950 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
23956     # check output
23957     (check-next-stream-line-equal _test-output-stream "(f 0x34)" "F - test-emit-subx-stmt-function-call-with-literal-arg")
23958     # . epilogue
23959     89/<- %esp 5/r32/ebp
23960     5d/pop-to-ebp
23961     c3/return
23962 
23963 emit-indent:  # out: (addr buffered-file), n: int
23964     # . prologue
23965     55/push-ebp
23966     89/<- %ebp 4/r32/esp
23967     # . save registers
23968     50/push-eax
23969     # var i/eax: int = n
23970     8b/-> *(ebp+0xc) 0/r32/eax
23971     {
23972       # if (i <= 0) break
23973       3d/compare-eax-with 0/imm32
23974       7e/jump-if-<= break/disp8
23975       (write-buffered *(ebp+8) "  ")
23976       48/decrement-eax
23977       eb/jump loop/disp8
23978     }
23979 $emit-indent:end:
23980     # . restore registers
23981     58/pop-to-eax
23982     # . epilogue
23983     89/<- %esp 5/r32/ebp
23984     5d/pop-to-ebp
23985     c3/return
23986 
23987 emit-subx-prologue:  # out: (addr buffered-file)
23988     # . prologue
23989     55/push-ebp
23990     89/<- %ebp 4/r32/esp
23991     #
23992     (write-buffered *(ebp+8) "  # . prologue\n")
23993     (write-buffered *(ebp+8) "  55/push-ebp\n")
23994     (write-buffered *(ebp+8) "  89/<- %ebp 4/r32/esp\n")
23995 $emit-subx-prologue:end:
23996     # . epilogue
23997     89/<- %esp 5/r32/ebp
23998     5d/pop-to-ebp
23999     c3/return
24000 
24001 emit-subx-epilogue:  # out: (addr buffered-file)
24002     # . prologue
24003     55/push-ebp
24004     89/<- %ebp 4/r32/esp
24005     #
24006     (write-buffered *(ebp+8) "  # . epilogue\n")
24007     (write-buffered *(ebp+8) "  89/<- %esp 5/r32/ebp\n")
24008     (write-buffered *(ebp+8) "  5d/pop-to-ebp\n")
24009     (write-buffered *(ebp+8) "  c3/return\n")
24010 $emit-subx-epilogue:end:
24011     # . epilogue
24012     89/<- %esp 5/r32/ebp
24013     5d/pop-to-ebp
24014     c3/return