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 #     subx-xm32: enum arg-location
  214 #     subx-x32: enum arg-location
  215 #   arg-location: enum
  216 #     0 means none
  217 #     1 means first inout
  218 #     2 means second inout
  219 #     3 means first output
  220 
  221 # == Translating a block
  222 # Emit block name if necessary
  223 # Emit '{'
  224 # When you encounter a statement, emit it as above
  225 # When you encounter a variable declaration
  226 #   emit any code needed for it (bzeros)
  227 #   push it on the var stack
  228 #   update register dict if necessary
  229 # When you encounter '}'
  230 #   While popping variables off the var stack until block id changes
  231 #     Emit code needed to clean up the stack
  232 #       either increment esp
  233 #       or pop into appropriate register
  234 
  235 # The rest is straightforward.
  236 
  237 == data
  238 
  239 Program:
  240 _Program-functions:  # (handle function)
  241   0/imm32
  242 _Program-functions->payload:
  243   0/imm32
  244 _Program-types:  # (handle typeinfo)
  245   0/imm32
  246 _Program-types->payload:
  247   0/imm32
  248 _Program-signatures:  # (handle function)
  249   0/imm32
  250 _Program-signatures->payload:
  251   0/imm32
  252 
  253 # Some constants for simulating the data structures described above.
  254 # Many constants here come with a type in a comment.
  255 #
  256 # Sometimes the type is of the value at that offset for the given type. For
  257 # example, if you start at a function record and move forward Function-inouts
  258 # bytes, you'll find a (handle list var).
  259 #
  260 # At other times, the type is of the constant itself. For example, the type of
  261 # the constant Function-size is (addr int). To get the size of a function,
  262 # look in *Function-size.
  263 
  264 Function-name:  # (handle array byte)
  265   0/imm32
  266 Function-inouts:  # (handle list var)
  267   8/imm32
  268 Function-outputs:  # (handle list var)
  269   0x10/imm32
  270 Function-body:  # (handle block)
  271   0x18/imm32
  272 Function-next:  # (handle function)
  273   0x20/imm32
  274 Function-size:  # (addr int)
  275   0x28/imm32/40
  276 
  277 Primitive-name:  # (handle array byte)
  278   0/imm32
  279 Primitive-inouts:  # (handle list var)
  280   8/imm32
  281 Primitive-outputs:  # (handle list var)
  282   0x10/imm32
  283 Primitive-subx-name:  # (handle array byte)
  284   0x18/imm32
  285 Primitive-subx-rm32:  # enum arg-location
  286   0x20/imm32
  287 Primitive-subx-r32:  # enum arg-location
  288   0x24/imm32
  289 Primitive-subx-imm32:  # enum arg-location
  290   0x28/imm32
  291 Primitive-subx-imm8:  # enum arg-location  -- only for bit shifts
  292   0x2c/imm32
  293 Primitive-subx-disp32:  # enum arg-location  -- only for branches
  294   0x30/imm32
  295 Primitive-subx-xm32:  # enum arg-location
  296   0x34/imm32
  297 Primitive-subx-x32:  # enum arg-location
  298   0x38/imm32
  299 Primitive-next:  # (handle function)
  300   0x3c/imm32
  301 Primitive-size:  # (addr int)
  302   0x44/imm32/68
  303 
  304 Stmt-tag:  # int
  305   0/imm32
  306 
  307 Block-stmts:  # (handle list stmt)
  308   4/imm32
  309 Block-var:  # (handle var)
  310   0xc/imm32
  311 
  312 Stmt1-operation:  # (handle array byte)
  313   4/imm32
  314 Stmt1-inouts:  # (handle stmt-var)
  315   0xc/imm32
  316 Stmt1-outputs:  # (handle stmt-var)
  317   0x14/imm32
  318 
  319 Vardef-var:  # (handle var)
  320   4/imm32
  321 
  322 Regvardef-operation:  # (handle array byte)
  323   4/imm32
  324 Regvardef-inouts:  # (handle stmt-var)
  325   0xc/imm32
  326 Regvardef-outputs:  # (handle stmt-var)  # will have exactly one element
  327   0x14/imm32
  328 
  329 Stmt-size:  # (addr int)
  330   0x1c/imm32
  331 
  332 Var-name:  # (handle array byte)
  333   0/imm32
  334 Var-type:  # (handle type-tree)
  335   8/imm32
  336 Var-block-depth:  # int -- not available until code-generation time
  337   0x10/imm32
  338 Var-offset:  # int -- not available until code-generation time
  339   0x14/imm32
  340 Var-register:  # (handle array byte) -- name of a register
  341   0x18/imm32
  342 Var-size:  # (addr int)
  343   0x20/imm32
  344 
  345 List-value:  # (handle _)
  346   0/imm32
  347 List-next:  # (handle list _)
  348   8/imm32
  349 List-size:  # (addr int)
  350   0x10/imm32
  351 
  352 # A stmt-var is like a list of vars with call-site specific metadata
  353 Stmt-var-value:  # (handle var)
  354   0/imm32
  355 Stmt-var-next:  # (handle stmt-var)
  356   8/imm32
  357 Stmt-var-is-deref:  # boolean
  358   0x10/imm32
  359 Stmt-var-size:  # (addr int)
  360   0x14/imm32
  361 
  362 # A live-var is a var augmented with information needed for tracking live
  363 # variables.
  364 Live-var-value:  # (handle var)
  365   0/imm32
  366 Live-var-register-spilled:  # boolean; only used if value is in a register, and only during code-gen
  367   8/imm32
  368 Live-var-size:  # (addr int)
  369   0xc/imm32
  370 
  371 # Types are expressed as trees (s-expressions) of type-ids (ints).
  372 
  373 Type-tree-is-atom:  # boolean
  374   0/imm32
  375 # if is-atom?
  376 Type-tree-value:  # type-id
  377   4/imm32
  378 Type-tree-value-size:  # int (for static data structure sizes)
  379   8/imm32
  380 Type-tree-parameter-name:  # (handle array byte) for type parameters
  381   8/imm32
  382 # unless is-atom?
  383 Type-tree-left:  # (addr type-tree)
  384   4/imm32
  385 Type-tree-right:  # (addr type-tree)
  386   0xc/imm32
  387 #
  388 Type-tree-size:  # (addr int)
  389   0x14/imm32
  390 
  391 # Types
  392 
  393 # TODO: Turn this data structure into valid Mu, with (fake) handles rather than addrs.
  394 Type-id:  # (stream (addr array byte))
  395   0/imm32/write  # initialized later from Primitive-type-ids
  396   0/imm32/read
  397   0x100/imm32/size
  398   # data
  399   0/imm32  # 0 reserved for literals; value is just the name
  400            # Not to be used directly, so we don't include a name here.
  401   "int"/imm32  # 1
  402   "addr"/imm32  # 2
  403   "array"/imm32  # 3
  404   "handle"/imm32  # 4
  405   "boolean"/imm32  # 5
  406   0/imm32  # 6 reserved for constants; they're like literals, but value is an int in Var-offset
  407            # Not to be used directly, so we don't include a name here.
  408   "offset"/imm32  # 7: (offset T) is guaranteed to be a 32-bit multiple of size-of(T)
  409   # 0x20
  410   "byte"/imm32  # 8
  411   0/imm32  # 9 reserved for array-capacity; value is in Type-tree-size.
  412            # Not to be used directly, so we don't include a name here.
  413   0/imm32  # 10 reserved for type parameters; value is (address array byte) in Type-tree-value2.
  414            # Not to be used directly, so we don't include a name here.
  415   "stream"/imm32  # 11
  416   "slice"/imm32  # 12
  417   "code-point"/imm32  # 13; smallest scannable unit from a text stream
  418   "grapheme"/imm32  # 14; smallest printable unit; will eventually be composed of multiple code-points, but currently corresponds 1:1
  419                     # only 4-byte graphemes in utf-8 are currently supported;
  420                     # unclear how we should deal with larger clusters.
  421   "float"/imm32     # 15
  422   # Keep Primitive-type-ids in sync if you add types here.
  423   # 0x40
  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   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  428   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  429   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  430 
  431 Primitive-type-ids:  # (addr int)
  432   0x40
  433 
  434 # == Type definitions
  435 # Program->types contains some typeinfo for each type definition.
  436 # Types contain vars with types, but can't specify registers.
  437 Typeinfo-id:  # type-id
  438   0/imm32
  439 Typeinfo-fields:  # (handle table (handle array byte) (handle typeinfo-entry))
  440   4/imm32
  441 # Total size must be >= 0
  442 # During parsing it may take on two additional values:
  443 #   -2: not yet initialized
  444 #   -1: in process of being computed
  445 # See populate-mu-type-sizes for details.
  446 Typeinfo-total-size-in-bytes:  # int
  447   0xc/imm32
  448 Typeinfo-next:  # (handle typeinfo)
  449   0x10/imm32
  450 Typeinfo-size:  # (addr int)
  451   0x18/imm32
  452 
  453 # Each entry in the typeinfo->fields table has a pointer to a string and a
  454 # pointer to a typeinfo-entry.
  455 Typeinfo-fields-row-size:  # (addr int)
  456   0x10/imm32
  457 
  458 # typeinfo-entry objects have information about a field in a single record type
  459 #
  460 # each field of a type is represented using two var's:
  461 #   1. the input var: expected type of the field; convenient for creating using parse-var-with-type
  462 #   2. the output var: a constant containing the byte offset; convenient for code-generation
  463 # computing the output happens after parsing; in the meantime we preserve the
  464 # order of fields in the 'index' field.
  465 Typeinfo-entry-input-var:  # (handle var)
  466   0/imm32
  467 Typeinfo-entry-index:  # int
  468   8/imm32
  469 Typeinfo-entry-output-var:  # (handle var)
  470   0xc/imm32
  471 Typeinfo-entry-size:  # (addr int)
  472   0x14/imm32
  473 
  474 == code
  475 
  476 Entry:
  477     # . prologue
  478     89/<- %ebp 4/r32/esp
  479     (new-segment *Heap-size Heap)
  480     # if (argv[1] == "test') run-tests()
  481     {
  482       # if (argc <= 1) break
  483       81 7/subop/compare *ebp 1/imm32
  484       7e/jump-if-<= break/disp8
  485       # if (argv[1] != "test") break
  486       (kernel-string-equal? *(ebp+8) "test")  # => eax
  487       3d/compare-eax-and 0/imm32/false
  488       74/jump-if-= break/disp8
  489       #
  490       (run-tests)
  491       # syscall(exit, *Num-test-failures)
  492       8b/-> *Num-test-failures 3/r32/ebx
  493       eb/jump $mu-main:end/disp8
  494     }
  495     # otherwise convert Stdin
  496     (convert-mu Stdin Stdout Stderr 0)
  497     (flush Stdout)
  498     # syscall(exit, 0)
  499     bb/copy-to-ebx 0/imm32
  500 $mu-main:end:
  501     e8/call syscall_exit/disp32
  502 
  503 convert-mu:  # in: (addr buffered-file), out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
  504     # . prologue
  505     55/push-ebp
  506     89/<- %ebp 4/r32/esp
  507     # . save registers
  508     50/push-eax
  509     # initialize global data structures
  510     c7 0/subop/copy *Next-block-index 1/imm32
  511     8b/-> *Primitive-type-ids 0/r32/eax
  512     89/<- *Type-id 0/r32/eax  # stream-write
  513     c7 0/subop/copy *_Program-functions 0/imm32
  514     c7 0/subop/copy *_Program-functions->payload 0/imm32
  515     c7 0/subop/copy *_Program-types 0/imm32
  516     c7 0/subop/copy *_Program-types->payload 0/imm32
  517     c7 0/subop/copy *_Program-signatures 0/imm32
  518     c7 0/subop/copy *_Program-signatures->payload 0/imm32
  519     #
  520     (parse-mu *(ebp+8) *(ebp+0x10) *(ebp+0x14))
  521     (populate-mu-type-sizes *(ebp+0x10) *(ebp+0x14))
  522 #?     (dump-typeinfos "=== typeinfos\n")
  523     (check-mu-types *(ebp+0x10) *(ebp+0x14))
  524     (emit-subx *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
  525 $convert-mu:end:
  526     # . restore registers
  527     58/pop-to-eax
  528     # . epilogue
  529     89/<- %esp 5/r32/ebp
  530     5d/pop-to-ebp
  531     c3/return
  532 
  533 test-convert-empty-input:
  534     # empty input => empty output
  535     # . prologue
  536     55/push-ebp
  537     89/<- %ebp 4/r32/esp
  538     # setup
  539     (clear-stream _test-input-stream)
  540     (clear-stream $_test-input-buffered-file->buffer)
  541     (clear-stream _test-output-stream)
  542     (clear-stream $_test-output-buffered-file->buffer)
  543     #
  544     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  545     (flush _test-output-buffered-file)
  546     (check-stream-equal _test-output-stream "" "F - test-convert-empty-input")
  547     # . epilogue
  548     89/<- %esp 5/r32/ebp
  549     5d/pop-to-ebp
  550     c3/return
  551 
  552 test-convert-function-skeleton:
  553     # . prologue
  554     55/push-ebp
  555     89/<- %ebp 4/r32/esp
  556     # setup
  557     (clear-stream _test-input-stream)
  558     (clear-stream $_test-input-buffered-file->buffer)
  559     (clear-stream _test-output-stream)
  560     (clear-stream $_test-output-buffered-file->buffer)
  561     #
  562     (write _test-input-stream "fn foo {\n")
  563     (write _test-input-stream "}\n")
  564     # convert
  565     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  566     (flush _test-output-buffered-file)
  567 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
  573     # check output
  574     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-skeleton/0")
  575     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-skeleton/1")
  576     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-skeleton/2")
  577     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-skeleton/3")
  578     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-skeleton/4")
  579     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-skeleton/5")
  580     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-skeleton/6")
  581     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-skeleton/7")
  582     # . epilogue
  583     89/<- %esp 5/r32/ebp
  584     5d/pop-to-ebp
  585     c3/return
  586 
  587 test-convert-multiple-function-skeletons:
  588     # . prologue
  589     55/push-ebp
  590     89/<- %ebp 4/r32/esp
  591     # setup
  592     (clear-stream _test-input-stream)
  593     (clear-stream $_test-input-buffered-file->buffer)
  594     (clear-stream _test-output-stream)
  595     (clear-stream $_test-output-buffered-file->buffer)
  596     #
  597     (write _test-input-stream "fn foo {\n")
  598     (write _test-input-stream "}\n")
  599     (write _test-input-stream "fn bar {\n")
  600     (write _test-input-stream "}\n")
  601     # convert
  602     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  603     (flush _test-output-buffered-file)
  604 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
  610     # check first function
  611     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-multiple-function-skeletons/0")
  612     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/1")
  613     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/2")
  614     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/3")
  615     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/4")
  616     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/5")
  617     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/6")
  618     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/7")
  619     # check second function
  620     (check-next-stream-line-equal _test-output-stream "bar:"                    "F - test-convert-multiple-function-skeletons/10")
  621     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/11")
  622     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/12")
  623     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/13")
  624     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/14")
  625     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/15")
  626     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/16")
  627     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/17")
  628     # . epilogue
  629     89/<- %esp 5/r32/ebp
  630     5d/pop-to-ebp
  631     c3/return
  632 
  633 test-convert-function-with-arg:
  634     # . prologue
  635     55/push-ebp
  636     89/<- %ebp 4/r32/esp
  637     # setup
  638     (clear-stream _test-input-stream)
  639     (clear-stream $_test-input-buffered-file->buffer)
  640     (clear-stream _test-output-stream)
  641     (clear-stream $_test-output-buffered-file->buffer)
  642     #
  643     (write _test-input-stream "fn foo n: int {\n")
  644     (write _test-input-stream "}\n")
  645     # convert
  646     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  647     (flush _test-output-buffered-file)
  648 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
  654     # check output
  655     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg/0")
  656     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg/1")
  657     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg/2")
  658     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg/3")
  659     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg/4")
  660     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg/5")
  661     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg/6")
  662     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg/7")
  663     # . epilogue
  664     89/<- %esp 5/r32/ebp
  665     5d/pop-to-ebp
  666     c3/return
  667 
  668 test-convert-function-with-arg-and-body:
  669     # . prologue
  670     55/push-ebp
  671     89/<- %ebp 4/r32/esp
  672     # setup
  673     (clear-stream _test-input-stream)
  674     (clear-stream $_test-input-buffered-file->buffer)
  675     (clear-stream _test-output-stream)
  676     (clear-stream $_test-output-buffered-file->buffer)
  677     #
  678     (write _test-input-stream "fn foo n: int {\n")
  679     (write _test-input-stream "  increment n\n")
  680     (write _test-input-stream "}\n")
  681     # convert
  682     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  683     (flush _test-output-buffered-file)
  684 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
  690     # check output
  691     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg-and-body/0")
  692     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg-and-body/1")
  693     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg-and-body/2")
  694     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg-and-body/3")
  695     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-arg-and-body/4")
  696     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-arg-and-body/5")
  697     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-arg-and-body/6")
  698     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-arg-and-body/7")
  699     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-arg-and-body/8")
  700     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg-and-body/9")
  701     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg-and-body/10")
  702     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg-and-body/11")
  703     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg-and-body/12")
  704     # . epilogue
  705     89/<- %esp 5/r32/ebp
  706     5d/pop-to-ebp
  707     c3/return
  708 
  709 test-convert-function-distinguishes-args:
  710     # . prologue
  711     55/push-ebp
  712     89/<- %ebp 4/r32/esp
  713     # setup
  714     (clear-stream _test-input-stream)
  715     (clear-stream $_test-input-buffered-file->buffer)
  716     (clear-stream _test-output-stream)
  717     (clear-stream $_test-output-buffered-file->buffer)
  718     #
  719     (write _test-input-stream "fn foo a: int, b: int {\n")
  720     (write _test-input-stream "  increment b\n")
  721     (write _test-input-stream "}\n")
  722     # convert
  723     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  724     (flush _test-output-buffered-file)
  725 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
  731     # check output
  732     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-distinguishes-args/0")
  733     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-distinguishes-args/1")
  734     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-distinguishes-args/2")
  735     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-distinguishes-args/3")
  736     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-distinguishes-args/4")
  737     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-distinguishes-args/5")
  738     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x0000000c)"  "F - test-convert-function-distinguishes-args/6")
  739     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-distinguishes-args/7")
  740     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-distinguishes-args/8")
  741     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-distinguishes-args/9")
  742     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-distinguishes-args/10")
  743     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-distinguishes-args/11")
  744     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-distinguishes-args/12")
  745     # . epilogue
  746     89/<- %esp 5/r32/ebp
  747     5d/pop-to-ebp
  748     c3/return
  749 
  750 test-convert-function-returns-result:
  751     # . prologue
  752     55/push-ebp
  753     89/<- %ebp 4/r32/esp
  754     # setup
  755     (clear-stream _test-input-stream)
  756     (clear-stream $_test-input-buffered-file->buffer)
  757     (clear-stream _test-output-stream)
  758     (clear-stream $_test-output-buffered-file->buffer)
  759     #
  760     (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n")
  761     (write _test-input-stream "  result <- copy a\n")
  762     (write _test-input-stream "  result <- increment\n")
  763     (write _test-input-stream "}\n")
  764     # convert
  765     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  766     (flush _test-output-buffered-file)
  767 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
  773     # check output
  774     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-returns-result/0")
  775     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-returns-result/1")
  776     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-returns-result/2")
  777     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-returns-result/3")
  778     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-returns-result/4")
  779     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-returns-result/5")
  780     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-returns-result/6")
  781     (check-next-stream-line-equal _test-output-stream "    40/increment-eax"    "F - test-convert-function-returns-result/7")
  782     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-returns-result/8")
  783     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-returns-result/9")
  784     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-returns-result/10")
  785     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-returns-result/11")
  786     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-returns-result/12")
  787     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-returns-result/13")
  788     # . epilogue
  789     89/<- %esp 5/r32/ebp
  790     5d/pop-to-ebp
  791     c3/return
  792 
  793 test-convert-function-with-literal-arg:
  794     # . prologue
  795     55/push-ebp
  796     89/<- %ebp 4/r32/esp
  797     # setup
  798     (clear-stream _test-input-stream)
  799     (clear-stream $_test-input-buffered-file->buffer)
  800     (clear-stream _test-output-stream)
  801     (clear-stream $_test-output-buffered-file->buffer)
  802     #
  803     (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n")
  804     (write _test-input-stream "  result <- copy a\n")
  805     (write _test-input-stream "  result <- add 1\n")
  806     (write _test-input-stream "}\n")
  807     # convert
  808     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  809     (flush _test-output-buffered-file)
  810 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
  816     # check output
  817     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg/0")
  818     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg/1")
  819     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg/2")
  820     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg/3")
  821     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg/4")
  822     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg/5")
  823     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-with-literal-arg/6")
  824     (check-next-stream-line-equal _test-output-stream "    05/add-to-eax 1/imm32"  "F - test-convert-function-with-literal-arg/7")
  825     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg/8")
  826     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg/9")
  827     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg/10")
  828     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg/11")
  829     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg/12")
  830     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg/13")
  831     # . epilogue
  832     89/<- %esp 5/r32/ebp
  833     5d/pop-to-ebp
  834     c3/return
  835 
  836 test-convert-function-with-literal-arg-2:
  837     # . prologue
  838     55/push-ebp
  839     89/<- %ebp 4/r32/esp
  840     # setup
  841     (clear-stream _test-input-stream)
  842     (clear-stream $_test-input-buffered-file->buffer)
  843     (clear-stream _test-output-stream)
  844     (clear-stream $_test-output-buffered-file->buffer)
  845     #
  846     (write _test-input-stream "fn foo a: int, b: int -> result/ebx: int {\n")
  847     (write _test-input-stream "  result <- copy a\n")
  848     (write _test-input-stream "  result <- add 1\n")
  849     (write _test-input-stream "}\n")
  850     # convert
  851     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  852     (flush _test-output-buffered-file)
  853 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
  859     # check output
  860     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg-2/0")
  861     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg-2/1")
  862     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg-2/2")
  863     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg-2/3")
  864     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg-2/4")
  865     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg-2/5")
  866     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-with-literal-arg-2/6")
  867     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %ebx 1/imm32"  "F - test-convert-function-with-literal-arg-2/7")
  868     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg-2/8")
  869     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg-2/9")
  870     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg-2/10")
  871     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg-2/11")
  872     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg-2/12")
  873     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg-2/13")
  874     # . epilogue
  875     89/<- %esp 5/r32/ebp
  876     5d/pop-to-ebp
  877     c3/return
  878 
  879 test-convert-function-call-with-literal-arg:
  880     # . prologue
  881     55/push-ebp
  882     89/<- %ebp 4/r32/esp
  883     # setup
  884     (clear-stream _test-input-stream)
  885     (clear-stream $_test-input-buffered-file->buffer)
  886     (clear-stream _test-output-stream)
  887     (clear-stream $_test-output-buffered-file->buffer)
  888     #
  889     (write _test-input-stream "fn main -> result/ebx: int {\n")
  890     (write _test-input-stream "  result <- do-add 3 4\n")
  891     (write _test-input-stream "}\n")
  892     (write _test-input-stream "fn do-add a: int, b: int -> result/ebx: int {\n")
  893     (write _test-input-stream "  result <- copy a\n")
  894     (write _test-input-stream "  result <- add b\n")
  895     (write _test-input-stream "}\n")
  896     # convert
  897     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  898     (flush _test-output-buffered-file)
  899 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
  905     # check output
  906     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call-with-literal-arg/0")
  907     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/1")
  908     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/2")
  909     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/3")
  910     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/4")
  911     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call-with-literal-arg/5")
  912     (check-next-stream-line-equal _test-output-stream "    (do-add 3 4)"        "F - test-convert-function-call-with-literal-arg/6")
  913     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/7")
  914     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-literal-arg/8")
  915     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/9")
  916     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/10")
  917     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/11")
  918     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/12")
  919     (check-next-stream-line-equal _test-output-stream "do-add:"                 "F - test-convert-function-call-with-literal-arg/13")
  920     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/14")
  921     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/15")
  922     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/16")
  923     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/17")
  924     (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:loop:"  "F - test-convert-function-call-with-literal-arg/18")
  925     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-call-with-literal-arg/19")
  926     (check-next-stream-line-equal _test-output-stream "    03/add *(ebp+0x0000000c) 0x00000003/r32"  "F - test-convert-function-call-with-literal-arg/20")
  927     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/21")
  928     (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:break:"  "F - test-convert-function-call-with-literal-arg/22")
  929     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/23")
  930     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/24")
  931     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/25")
  932     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/26")
  933     # . epilogue
  934     89/<- %esp 5/r32/ebp
  935     5d/pop-to-ebp
  936     c3/return
  937 
  938 test-convert-function-call-with-signature:
  939     # . prologue
  940     55/push-ebp
  941     89/<- %ebp 4/r32/esp
  942     # setup
  943     (clear-stream _test-input-stream)
  944     (clear-stream $_test-input-buffered-file->buffer)
  945     (clear-stream _test-output-stream)
  946     (clear-stream $_test-output-buffered-file->buffer)
  947     #
  948     (write _test-input-stream "fn main -> result/ebx: int {\n")
  949     (write _test-input-stream "  result <- do-add 3 4\n")
  950     (write _test-input-stream "}\n")
  951     (write _test-input-stream "sig do-add a: int, b: int -> result/ebx: int\n")
  952     # convert
  953     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  954     (flush _test-output-buffered-file)
  955 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
  961     # check output
  962     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call-with-signature/0")
  963     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-signature/1")
  964     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-signature/2")
  965     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-signature/3")
  966     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-signature/4")
  967     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call-with-signature/5")
  968     (check-next-stream-line-equal _test-output-stream "    (do-add 3 4)"        "F - test-convert-function-call-with-signature/6")
  969     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-signature/7")
  970     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-signature/8")
  971     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-signature/9")
  972     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-signature/10")
  973     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-signature/11")
  974     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-signature/12")
  975     # . epilogue
  976     89/<- %esp 5/r32/ebp
  977     5d/pop-to-ebp
  978     c3/return
  979 
  980 test-convert-function-with-local-var-in-mem:
  981     # . prologue
  982     55/push-ebp
  983     89/<- %ebp 4/r32/esp
  984     # setup
  985     (clear-stream _test-input-stream)
  986     (clear-stream $_test-input-buffered-file->buffer)
  987     (clear-stream _test-output-stream)
  988     (clear-stream $_test-output-buffered-file->buffer)
  989     #
  990     (write _test-input-stream "fn foo {\n")
  991     (write _test-input-stream "  var x: int\n")
  992     (write _test-input-stream "  increment x\n")
  993     (write _test-input-stream "}\n")
  994     # convert
  995     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  996     (flush _test-output-buffered-file)
  997 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1003     # check output
 1004     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-mem/0")
 1005     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-mem/1")
 1006     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-mem/2")
 1007     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-mem/3")
 1008     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-mem/4")
 1009     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-mem/5")
 1010     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-in-mem/6")
 1011     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-mem/7")
 1012     (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")
 1013     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-mem/9")
 1014     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-mem/10")
 1015     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-mem/11")
 1016     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-mem/12")
 1017     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-mem/13")
 1018     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-mem/14")
 1019     # . epilogue
 1020     89/<- %esp 5/r32/ebp
 1021     5d/pop-to-ebp
 1022     c3/return
 1023 
 1024 test-convert-invalid-literal:
 1025     # . prologue
 1026     55/push-ebp
 1027     89/<- %ebp 4/r32/esp
 1028     # setup
 1029     (clear-stream _test-input-stream)
 1030     (clear-stream $_test-input-buffered-file->buffer)
 1031     (clear-stream _test-output-stream)
 1032     (clear-stream $_test-output-buffered-file->buffer)
 1033     (clear-stream _test-error-stream)
 1034     (clear-stream $_test-error-buffered-file->buffer)
 1035     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1036     68/push 0/imm32
 1037     68/push 0/imm32
 1038     89/<- %edx 4/r32/esp
 1039     (tailor-exit-descriptor %edx 0x10)
 1040     #
 1041     (write _test-input-stream "fn foo {\n")
 1042     (write _test-input-stream "  increment 1n\n")
 1043     (write _test-input-stream "}\n")
 1044     # convert
 1045     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1046     # registers except esp clobbered at this point
 1047     # restore ed
 1048     89/<- %edx 4/r32/esp
 1049     (flush _test-output-buffered-file)
 1050     (flush _test-error-buffered-file)
 1051 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1057     # check output
 1058     (check-stream-equal _test-output-stream  ""  "F - test-convert-invalid-literal: output should be empty")
 1059     (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")
 1060     # check that stop(1) was called
 1061     (check-ints-equal *(edx+4) 2 "F - test-convert-invalid-literal: exit status")
 1062     # don't restore from ebp
 1063     81 0/subop/add %esp 8/imm32
 1064     # . epilogue
 1065     5d/pop-to-ebp
 1066     c3/return
 1067 
 1068 test-local-var-in-mem-has-no-initializer:
 1069     # . prologue
 1070     55/push-ebp
 1071     89/<- %ebp 4/r32/esp
 1072     # setup
 1073     (clear-stream _test-input-stream)
 1074     (clear-stream $_test-input-buffered-file->buffer)
 1075     (clear-stream _test-output-stream)
 1076     (clear-stream $_test-output-buffered-file->buffer)
 1077     (clear-stream _test-error-stream)
 1078     (clear-stream $_test-error-buffered-file->buffer)
 1079     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1080     68/push 0/imm32
 1081     68/push 0/imm32
 1082     89/<- %edx 4/r32/esp
 1083     (tailor-exit-descriptor %edx 0x10)
 1084     #
 1085     (write _test-input-stream "fn foo {\n")
 1086     (write _test-input-stream "  var x: int <- copy 0\n")
 1087     (write _test-input-stream "  increment x\n")
 1088     (write _test-input-stream "}\n")
 1089     # convert
 1090     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1091     # registers except esp clobbered at this point
 1092     # restore ed
 1093     89/<- %edx 4/r32/esp
 1094     (flush _test-output-buffered-file)
 1095     (flush _test-error-buffered-file)
 1096 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1102     # check output
 1103     (check-stream-equal _test-output-stream  ""  "F - test-var-in-mem-has-no-initializer: output should be empty")
 1104     (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")
 1105     # check that stop(1) was called
 1106     (check-ints-equal *(edx+4) 2 "F - test-var-in-mem-has-no-initializer: exit status")
 1107     # don't restore from ebp
 1108     81 0/subop/add %esp 8/imm32
 1109     # . epilogue
 1110     5d/pop-to-ebp
 1111     c3/return
 1112 
 1113 test-convert-function-with-local-var-with-compound-type-in-mem:
 1114     # . prologue
 1115     55/push-ebp
 1116     89/<- %ebp 4/r32/esp
 1117     # setup
 1118     (clear-stream _test-input-stream)
 1119     (clear-stream $_test-input-buffered-file->buffer)
 1120     (clear-stream _test-output-stream)
 1121     (clear-stream $_test-output-buffered-file->buffer)
 1122     #
 1123     (write _test-input-stream "fn foo {\n")
 1124     (write _test-input-stream "  var x: (addr int)\n")
 1125     (write _test-input-stream "  copy-to x, 0\n")
 1126     (write _test-input-stream "}\n")
 1127     # convert
 1128     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1129     (flush _test-output-buffered-file)
 1130 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1136     # check output
 1137     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-compound-type-in-mem/0")
 1138     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/1")
 1139     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-compound-type-in-mem/2")
 1140     (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")
 1141     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/4")
 1142     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-compound-type-in-mem/5")
 1143     (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")
 1144     (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")
 1145     (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")
 1146     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/9")
 1147     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/10")
 1148     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/11")
 1149     (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")
 1150     (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")
 1151     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-compound-type-in-mem/14")
 1152     # . epilogue
 1153     89/<- %esp 5/r32/ebp
 1154     5d/pop-to-ebp
 1155     c3/return
 1156 
 1157 test-convert-function-with-local-var-in-reg:
 1158     # . prologue
 1159     55/push-ebp
 1160     89/<- %ebp 4/r32/esp
 1161     # setup
 1162     (clear-stream _test-input-stream)
 1163     (clear-stream $_test-input-buffered-file->buffer)
 1164     (clear-stream _test-output-stream)
 1165     (clear-stream $_test-output-buffered-file->buffer)
 1166     #
 1167     (write _test-input-stream "fn foo {\n")
 1168     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1169     (write _test-input-stream "  x <- increment\n")
 1170     (write _test-input-stream "}\n")
 1171     # convert
 1172     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1173     (flush _test-output-buffered-file)
 1174 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1180     # check output
 1181     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-reg/0")
 1182     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-reg/1")
 1183     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-reg/2")
 1184     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-reg/3")
 1185     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-reg/4")
 1186     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-reg/5")
 1187     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-in-reg/6")
 1188     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-convert-function-with-local-var-in-reg/7")
 1189     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-local-var-in-reg/8")
 1190     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-in-reg/9")
 1191     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-reg/10")
 1192     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-reg/11")
 1193     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-reg/12")
 1194     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-reg/13")
 1195     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-reg/14")
 1196     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-reg/15")
 1197     # . epilogue
 1198     89/<- %esp 5/r32/ebp
 1199     5d/pop-to-ebp
 1200     c3/return
 1201 
 1202 test-convert-function-with-allocate:
 1203     # . prologue
 1204     55/push-ebp
 1205     89/<- %ebp 4/r32/esp
 1206     # setup
 1207     (clear-stream _test-input-stream)
 1208     (clear-stream $_test-input-buffered-file->buffer)
 1209     (clear-stream _test-output-stream)
 1210     (clear-stream $_test-output-buffered-file->buffer)
 1211     #
 1212     (write _test-input-stream "fn foo {\n")
 1213     (write _test-input-stream "  var x/ecx: (addr handle int) <- copy 0\n")
 1214     (write _test-input-stream "  allocate x\n")
 1215     (write _test-input-stream "}\n")
 1216     # convert
 1217     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1218     (flush _test-output-buffered-file)
 1219 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1225     # check output
 1226     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-allocate/0")
 1227     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-allocate/1")
 1228     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-allocate/2")
 1229     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-allocate/3")
 1230     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-allocate/4")
 1231     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-allocate/5")
 1232     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-allocate/6")
 1233     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-allocate/7")
 1234     (check-next-stream-line-equal _test-output-stream "    (allocate Heap 0x00000004 %ecx)"  "F - test-convert-function-with-allocate/8")  # 4 = size-of(int)
 1235     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-allocate/9")
 1236     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-allocate/10")
 1237     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-allocate/11")
 1238     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-allocate/12")
 1239     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-allocate/13")
 1240     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-allocate/14")
 1241     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-allocate/15")
 1242     # . epilogue
 1243     89/<- %esp 5/r32/ebp
 1244     5d/pop-to-ebp
 1245     c3/return
 1246 
 1247 test-initializer-in-hex:
 1248     # . prologue
 1249     55/push-ebp
 1250     89/<- %ebp 4/r32/esp
 1251     # setup
 1252     (clear-stream _test-input-stream)
 1253     (clear-stream $_test-input-buffered-file->buffer)
 1254     (clear-stream _test-output-stream)
 1255     (clear-stream $_test-output-buffered-file->buffer)
 1256     (clear-stream _test-error-stream)
 1257     (clear-stream $_test-error-buffered-file->buffer)
 1258     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1259     68/push 0/imm32
 1260     68/push 0/imm32
 1261     89/<- %edx 4/r32/esp
 1262     (tailor-exit-descriptor %edx 0x10)
 1263     #
 1264     (write _test-input-stream "fn foo {\n")
 1265     (write _test-input-stream "  var x/ecx: int <- copy 10\n")
 1266     (write _test-input-stream "}\n")
 1267     # convert
 1268     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1269     # registers except esp clobbered at this point
 1270     # restore ed
 1271     89/<- %edx 4/r32/esp
 1272     (flush _test-output-buffered-file)
 1273     (flush _test-error-buffered-file)
 1274 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1280     # check output
 1281     (check-stream-equal _test-output-stream  ""  "F - test-initializer-in-hex: output should be empty")
 1282     (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")
 1283     # check that stop(1) was called
 1284     (check-ints-equal *(edx+4) 2 "F - test-initializer-in-hex: exit status")
 1285     # don't restore from ebp
 1286     81 0/subop/add %esp 8/imm32
 1287     # . epilogue
 1288     5d/pop-to-ebp
 1289     c3/return
 1290 
 1291 test-convert-function-with-second-local-var-in-same-reg:
 1292     # . prologue
 1293     55/push-ebp
 1294     89/<- %ebp 4/r32/esp
 1295     # setup
 1296     (clear-stream _test-input-stream)
 1297     (clear-stream $_test-input-buffered-file->buffer)
 1298     (clear-stream _test-output-stream)
 1299     (clear-stream $_test-output-buffered-file->buffer)
 1300     #
 1301     (write _test-input-stream "fn foo {\n")
 1302     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1303     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1304     (write _test-input-stream "  y <- increment\n")
 1305     (write _test-input-stream "}\n")
 1306     # convert
 1307     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1308     (flush _test-output-buffered-file)
 1309 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1315     # check output
 1316     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-second-local-var-in-same-reg/0")
 1317     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-second-local-var-in-same-reg/1")
 1318     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-second-local-var-in-same-reg/2")
 1319     (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")
 1320     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-second-local-var-in-same-reg/4")
 1321     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-second-local-var-in-same-reg/5")
 1322     (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")
 1323     (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")
 1324     (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")
 1325     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-second-local-var-in-same-reg/9")
 1326     (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")
 1327     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-second-local-var-in-same-reg/11")
 1328     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-second-local-var-in-same-reg/12")
 1329     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-second-local-var-in-same-reg/13")
 1330     (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")
 1331     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-second-local-var-in-same-reg/15")
 1332     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-second-local-var-in-same-reg/16")
 1333     # . epilogue
 1334     89/<- %esp 5/r32/ebp
 1335     5d/pop-to-ebp
 1336     c3/return
 1337 
 1338 test-read-clobbered-reg-var:
 1339     # . prologue
 1340     55/push-ebp
 1341     89/<- %ebp 4/r32/esp
 1342     # setup
 1343     (clear-stream _test-input-stream)
 1344     (clear-stream $_test-input-buffered-file->buffer)
 1345     (clear-stream _test-output-stream)
 1346     (clear-stream $_test-output-buffered-file->buffer)
 1347     (clear-stream _test-error-stream)
 1348     (clear-stream $_test-error-buffered-file->buffer)
 1349     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)  # bytes of args in call to convert-mu
 1350     68/push 0/imm32
 1351     68/push 0/imm32
 1352     89/<- %edx 4/r32/esp
 1353     (tailor-exit-descriptor %edx 0x10)
 1354     #
 1355     (write _test-input-stream "fn foo {\n")
 1356     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1357     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1358     (write _test-input-stream "  x <- increment\n")
 1359     (write _test-input-stream "}\n")
 1360     # convert
 1361     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1362     # registers except esp clobbered at this point
 1363     # restore ed
 1364     89/<- %edx 4/r32/esp
 1365     (flush _test-output-buffered-file)
 1366     (flush _test-error-buffered-file)
 1367 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1373     # check output
 1374     (check-stream-equal _test-output-stream  ""  "F - test-read-clobbered-reg-var: output should be empty")
 1375     (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")
 1376     # check that stop(1) was called
 1377     (check-ints-equal *(edx+4) 2 "F - test-read-clobbered-reg-var: exit status")
 1378     # don't restore from ebp
 1379     81 0/subop/add %esp 8/imm32
 1380     # . epilogue
 1381     5d/pop-to-ebp
 1382     c3/return
 1383 
 1384 test-convert-function-call:
 1385     # . prologue
 1386     55/push-ebp
 1387     89/<- %ebp 4/r32/esp
 1388     # setup
 1389     (clear-stream _test-input-stream)
 1390     (clear-stream $_test-input-buffered-file->buffer)
 1391     (clear-stream _test-output-stream)
 1392     (clear-stream $_test-output-buffered-file->buffer)
 1393     #
 1394     (write _test-input-stream "fn main -> result/ebx: int {\n")
 1395     (write _test-input-stream "  result <- foo\n")
 1396     (write _test-input-stream "}\n")
 1397     (write _test-input-stream "fn foo -> result/ebx: int {\n")
 1398     (write _test-input-stream "  result <- copy 3\n")
 1399     (write _test-input-stream "}\n")
 1400     # convert
 1401     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1402     (flush _test-output-buffered-file)
 1403 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1409     # check output
 1410     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call/0")
 1411     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call/1")
 1412     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call/2")
 1413     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call/3")
 1414     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call/4")
 1415     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call/5")
 1416     (check-next-stream-line-equal _test-output-stream "    (foo)"               "F - test-convert-function-call/6")
 1417     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call/7")
 1418     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call/8")
 1419     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call/9")
 1420     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call/10")
 1421     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call/11")
 1422     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call/12")
 1423     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call/13")
 1424     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call/14")
 1425     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call/15")
 1426     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call/16")
 1427     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call/17")
 1428     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"  "F - test-convert-function-call/18")
 1429     (check-next-stream-line-equal _test-output-stream "    bb/copy-to-ebx 3/imm32"  "F - test-convert-function-call/19")
 1430     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call/20")
 1431     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-call/21")
 1432     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call/22")
 1433     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call/23")
 1434     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call/24")
 1435     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call/25")
 1436     # . epilogue
 1437     89/<- %esp 5/r32/ebp
 1438     5d/pop-to-ebp
 1439     c3/return
 1440 
 1441 test-convert-function-call-with-inout-with-compound-type:
 1442     # . prologue
 1443     55/push-ebp
 1444     89/<- %ebp 4/r32/esp
 1445     # setup
 1446     (clear-stream _test-input-stream)
 1447     (clear-stream $_test-input-buffered-file->buffer)
 1448     (clear-stream _test-output-stream)
 1449     (clear-stream $_test-output-buffered-file->buffer)
 1450     #
 1451     (write _test-input-stream "fn f {\n")
 1452     (write _test-input-stream "  var x: (addr int)\n")
 1453     (write _test-input-stream "  g x\n")
 1454     (write _test-input-stream "}\n")
 1455     (write _test-input-stream "fn g a: (addr int) {\n")
 1456     (write _test-input-stream "}\n")
 1457     # convert
 1458     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1459     (flush _test-output-buffered-file)
 1460 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1466     # check output
 1467     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-inout-with-compound-type/0")
 1468     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-inout-with-compound-type/1")
 1469     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-inout-with-compound-type/2")
 1470     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-inout-with-compound-type/3")
 1471     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-inout-with-compound-type/4")
 1472     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-inout-with-compound-type/5")
 1473     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-inout-with-compound-type/6")
 1474     (check-next-stream-line-equal _test-output-stream "    (g *(ebp+0xfffffffc))"  "F - test-convert-function-call-with-inout-with-compound-type/7")
 1475     (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")
 1476     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-inout-with-compound-type/9")
 1477     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-inout-with-compound-type/10")
 1478     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-inout-with-compound-type/11")
 1479     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-inout-with-compound-type/12")
 1480     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-inout-with-compound-type/13")
 1481     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-inout-with-compound-type/14")
 1482     (check-next-stream-line-equal _test-output-stream "g:"                      "F - test-convert-function-call-with-inout-with-compound-type/15")
 1483     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-inout-with-compound-type/16")
 1484     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-inout-with-compound-type/17")
 1485     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-inout-with-compound-type/18")
 1486     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-inout-with-compound-type/19")
 1487     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-inout-with-compound-type/20")
 1488     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-inout-with-compound-type/21")
 1489     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-inout-with-compound-type/22")
 1490     # . epilogue
 1491     89/<- %esp 5/r32/ebp
 1492     5d/pop-to-ebp
 1493     c3/return
 1494 
 1495 test-convert-function-call-with-inout-with-type-parameter:
 1496     # . prologue
 1497     55/push-ebp
 1498     89/<- %ebp 4/r32/esp
 1499     # setup
 1500     (clear-stream _test-input-stream)
 1501     (clear-stream $_test-input-buffered-file->buffer)
 1502     (clear-stream _test-output-stream)
 1503     (clear-stream $_test-output-buffered-file->buffer)
 1504     (clear-stream _test-error-stream)
 1505     (clear-stream $_test-error-buffered-file->buffer)
 1506     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1507     68/push 0/imm32
 1508     68/push 0/imm32
 1509     89/<- %edx 4/r32/esp
 1510     (tailor-exit-descriptor %edx 0x10)
 1511     #
 1512     (write _test-input-stream "fn f {\n")
 1513     (write _test-input-stream "  var x: (addr int)\n")
 1514     (write _test-input-stream "  g x\n")
 1515     (write _test-input-stream "}\n")
 1516     (write _test-input-stream "fn g a: (addr _) {\n")
 1517     (write _test-input-stream "}\n")
 1518     # convert
 1519     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1520     # registers except esp clobbered at this point
 1521     # restore ed
 1522     89/<- %edx 4/r32/esp
 1523     (flush _test-output-buffered-file)
 1524     (flush _test-error-buffered-file)
 1525 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1531     # no error; types matched
 1532     (check-stream-equal _test-error-stream  ""  "F - test-convert-function-call-with-inout-with-type-parameter: error stream should be empty")
 1533     # don't bother checking the generated code; that's in the test 'test-local-clobbered-by-fn-output' below
 1534     # don't restore from ebp
 1535     81 0/subop/add %esp 8/imm32
 1536     # . epilogue
 1537     5d/pop-to-ebp
 1538     c3/return
 1539 
 1540 test-convert-function-call-with-incorrect-inout-type:
 1541     # . prologue
 1542     55/push-ebp
 1543     89/<- %ebp 4/r32/esp
 1544     # setup
 1545     (clear-stream _test-input-stream)
 1546     (clear-stream $_test-input-buffered-file->buffer)
 1547     (clear-stream _test-output-stream)
 1548     (clear-stream $_test-output-buffered-file->buffer)
 1549     (clear-stream _test-error-stream)
 1550     (clear-stream $_test-error-buffered-file->buffer)
 1551     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1552     68/push 0/imm32
 1553     68/push 0/imm32
 1554     89/<- %edx 4/r32/esp
 1555     (tailor-exit-descriptor %edx 0x10)
 1556     #
 1557     (write _test-input-stream "fn f {\n")
 1558     (write _test-input-stream "  var x: int\n")
 1559     (write _test-input-stream "  g x\n")
 1560     (write _test-input-stream "}\n")
 1561     (write _test-input-stream "fn g a: foo {\n")
 1562     (write _test-input-stream "}\n")
 1563     # convert
 1564     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1565     # registers except esp clobbered at this point
 1566     # restore ed
 1567     89/<- %edx 4/r32/esp
 1568     (flush _test-output-buffered-file)
 1569     (flush _test-error-buffered-file)
 1570 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1576     # check output
 1577     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-inout-type: output should be empty")
 1578     (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")
 1579     # check that stop(1) was called
 1580     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-inout-type: exit status")
 1581     # don't restore from ebp
 1582     81 0/subop/add %esp 8/imm32
 1583     5d/pop-to-ebp
 1584     c3/return
 1585 
 1586 test-convert-function-call-with-inout-with-incorrect-compound-type:
 1587     # . prologue
 1588     55/push-ebp
 1589     89/<- %ebp 4/r32/esp
 1590     # setup
 1591     (clear-stream _test-input-stream)
 1592     (clear-stream $_test-input-buffered-file->buffer)
 1593     (clear-stream _test-output-stream)
 1594     (clear-stream $_test-output-buffered-file->buffer)
 1595     (clear-stream _test-error-stream)
 1596     (clear-stream $_test-error-buffered-file->buffer)
 1597     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1598     68/push 0/imm32
 1599     68/push 0/imm32
 1600     89/<- %edx 4/r32/esp
 1601     (tailor-exit-descriptor %edx 0x10)
 1602     #
 1603     (write _test-input-stream "fn f {\n")
 1604     (write _test-input-stream "  var x: (addr int)\n")
 1605     (write _test-input-stream "  g x\n")
 1606     (write _test-input-stream "}\n")
 1607     (write _test-input-stream "fn g a: (addr bool) {\n")
 1608     (write _test-input-stream "}\n")
 1609     # convert
 1610     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1611     # registers except esp clobbered at this point
 1612     # restore ed
 1613     89/<- %edx 4/r32/esp
 1614     (flush _test-output-buffered-file)
 1615     (flush _test-error-buffered-file)
 1616 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1622     # check output
 1623     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-inout-with-incorrect-compound-type: output should be empty")
 1624     (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")
 1625     # don't restore from ebp
 1626     81 0/subop/add %esp 8/imm32
 1627     # . epilogue
 1628     5d/pop-to-ebp
 1629     c3/return
 1630 
 1631 test-convert-function-call-with-inout-with-multiple-type-parameters:
 1632     # . prologue
 1633     55/push-ebp
 1634     89/<- %ebp 4/r32/esp
 1635     # setup
 1636     (clear-stream _test-input-stream)
 1637     (clear-stream $_test-input-buffered-file->buffer)
 1638     (clear-stream _test-output-stream)
 1639     (clear-stream $_test-output-buffered-file->buffer)
 1640     (clear-stream _test-error-stream)
 1641     (clear-stream $_test-error-buffered-file->buffer)
 1642     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1643     68/push 0/imm32
 1644     68/push 0/imm32
 1645     89/<- %edx 4/r32/esp
 1646     (tailor-exit-descriptor %edx 0x10)
 1647     #
 1648     (write _test-input-stream "fn f {\n")
 1649     (write _test-input-stream "  var x: (addr int)\n")
 1650     (write _test-input-stream "  var y: (addr int)\n")
 1651     (write _test-input-stream "  g x, y\n")
 1652     (write _test-input-stream "}\n")
 1653     (write _test-input-stream "fn g a: (addr _), b: (addr _) {\n")
 1654     (write _test-input-stream "}\n")
 1655     # convert
 1656     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1657     # registers except esp clobbered at this point
 1658     # restore ed
 1659     89/<- %edx 4/r32/esp
 1660     (flush _test-output-buffered-file)
 1661     (flush _test-error-buffered-file)
 1662 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1668     # no errors
 1669     (check-stream-equal _test-error-stream  ""  "F - test-convert-function-call-with-inout-with-multiple-type-parameters: error stream should be empty")
 1670     # don't bother checking the generated code
 1671     # don't restore from ebp
 1672     81 0/subop/add %esp 8/imm32
 1673     # . epilogue
 1674     5d/pop-to-ebp
 1675     c3/return
 1676 
 1677 test-type-parameter-matches-rest-of-type:
 1678     # . prologue
 1679     55/push-ebp
 1680     89/<- %ebp 4/r32/esp
 1681     # setup
 1682     (clear-stream _test-input-stream)
 1683     (clear-stream $_test-input-buffered-file->buffer)
 1684     (clear-stream _test-output-stream)
 1685     (clear-stream $_test-output-buffered-file->buffer)
 1686     (clear-stream _test-error-stream)
 1687     (clear-stream $_test-error-buffered-file->buffer)
 1688     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1689     68/push 0/imm32
 1690     68/push 0/imm32
 1691     89/<- %edx 4/r32/esp
 1692     (tailor-exit-descriptor %edx 0x10)
 1693     #
 1694     (write _test-input-stream "fn f {\n")
 1695     (write _test-input-stream "  var x: (addr array int)\n")
 1696     (write _test-input-stream "  g x\n")
 1697     (write _test-input-stream "}\n")
 1698     (write _test-input-stream "fn g a: (addr _) {\n")
 1699     (write _test-input-stream "}\n")
 1700     # convert
 1701     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1702     # registers except esp clobbered at this point
 1703     # restore ed
 1704     89/<- %edx 4/r32/esp
 1705     (flush _test-output-buffered-file)
 1706     (flush _test-error-buffered-file)
 1707 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1713     # no errors
 1714     (check-stream-equal _test-error-stream  ""  "F - test-type-parameter-matches-rest-of-type: error stream should be empty")
 1715     # don't bother checking the generated code
 1716     # don't restore from ebp
 1717     81 0/subop/add %esp 8/imm32
 1718     # . epilogue
 1719     5d/pop-to-ebp
 1720     c3/return
 1721 
 1722 test-convert-function-call-with-inout-with-incompatible-type-parameters:
 1723     # . prologue
 1724     55/push-ebp
 1725     89/<- %ebp 4/r32/esp
 1726     # setup
 1727     (clear-stream _test-input-stream)
 1728     (clear-stream $_test-input-buffered-file->buffer)
 1729     (clear-stream _test-output-stream)
 1730     (clear-stream $_test-output-buffered-file->buffer)
 1731     (clear-stream _test-error-stream)
 1732     (clear-stream $_test-error-buffered-file->buffer)
 1733     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1734     68/push 0/imm32
 1735     68/push 0/imm32
 1736     89/<- %edx 4/r32/esp
 1737     (tailor-exit-descriptor %edx 0x10)
 1738     #
 1739     (write _test-input-stream "fn f {\n")
 1740     (write _test-input-stream "  var x: (addr int)\n")
 1741     (write _test-input-stream "  var y: (addr boolean)\n")
 1742     (write _test-input-stream "  g x, y\n")
 1743     (write _test-input-stream "}\n")
 1744     (write _test-input-stream "fn g a: (addr _T), b: (addr _T) {\n")
 1745     (write _test-input-stream "}\n")
 1746     # convert
 1747     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1748     # registers except esp clobbered at this point
 1749     # restore ed
 1750     89/<- %edx 4/r32/esp
 1751     (flush _test-output-buffered-file)
 1752     (flush _test-error-buffered-file)
 1753 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1759     # check output
 1760     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-inout-with-incompatible-type-parameters: output should be empty")
 1761     (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")
 1762     # don't restore from ebp
 1763     81 0/subop/add %esp 8/imm32
 1764     # . epilogue
 1765     5d/pop-to-ebp
 1766     c3/return
 1767 
 1768 test-convert-function-call-with-too-few-inouts:
 1769     # . prologue
 1770     55/push-ebp
 1771     89/<- %ebp 4/r32/esp
 1772     # setup
 1773     (clear-stream _test-input-stream)
 1774     (clear-stream $_test-input-buffered-file->buffer)
 1775     (clear-stream _test-output-stream)
 1776     (clear-stream $_test-output-buffered-file->buffer)
 1777     (clear-stream _test-error-stream)
 1778     (clear-stream $_test-error-buffered-file->buffer)
 1779     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1780     68/push 0/imm32
 1781     68/push 0/imm32
 1782     89/<- %edx 4/r32/esp
 1783     (tailor-exit-descriptor %edx 0x10)
 1784     #
 1785     (write _test-input-stream "fn f {\n")
 1786     (write _test-input-stream "  g\n")
 1787     (write _test-input-stream "}\n")
 1788     (write _test-input-stream "fn g a: int {\n")
 1789     (write _test-input-stream "}\n")
 1790     # convert
 1791     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1792     # registers except esp clobbered at this point
 1793     # restore ed
 1794     89/<- %edx 4/r32/esp
 1795     (flush _test-output-buffered-file)
 1796     (flush _test-error-buffered-file)
 1797 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1803     # check output
 1804     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-few-inouts: output should be empty")
 1805     (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")
 1806     # check that stop(1) was called
 1807     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-few-inouts: exit status")
 1808     # don't restore from ebp
 1809     81 0/subop/add %esp 8/imm32
 1810     5d/pop-to-ebp
 1811     c3/return
 1812 
 1813 test-convert-function-call-with-too-many-inouts:
 1814     # . prologue
 1815     55/push-ebp
 1816     89/<- %ebp 4/r32/esp
 1817     # setup
 1818     (clear-stream _test-input-stream)
 1819     (clear-stream $_test-input-buffered-file->buffer)
 1820     (clear-stream _test-output-stream)
 1821     (clear-stream $_test-output-buffered-file->buffer)
 1822     (clear-stream _test-error-stream)
 1823     (clear-stream $_test-error-buffered-file->buffer)
 1824     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1825     68/push 0/imm32
 1826     68/push 0/imm32
 1827     89/<- %edx 4/r32/esp
 1828     (tailor-exit-descriptor %edx 0x10)
 1829     #
 1830     (write _test-input-stream "fn f {\n")
 1831     (write _test-input-stream "  var x: int\n")
 1832     (write _test-input-stream "  g x\n")
 1833     (write _test-input-stream "}\n")
 1834     (write _test-input-stream "fn g {\n")
 1835     (write _test-input-stream "}\n")
 1836     # convert
 1837     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1838     # registers except esp clobbered at this point
 1839     # restore ed
 1840     89/<- %edx 4/r32/esp
 1841     (flush _test-output-buffered-file)
 1842     (flush _test-error-buffered-file)
 1843 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1849     # check output
 1850     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-many-inouts: output should be empty")
 1851     (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")
 1852     # check that stop(1) was called
 1853     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-many-inouts: exit status")
 1854     # don't restore from ebp
 1855     81 0/subop/add %esp 8/imm32
 1856     5d/pop-to-ebp
 1857     c3/return
 1858 
 1859 test-convert-function-call-with-incorrect-output-type:
 1860     # . prologue
 1861     55/push-ebp
 1862     89/<- %ebp 4/r32/esp
 1863     # setup
 1864     (clear-stream _test-input-stream)
 1865     (clear-stream $_test-input-buffered-file->buffer)
 1866     (clear-stream _test-output-stream)
 1867     (clear-stream $_test-output-buffered-file->buffer)
 1868     (clear-stream _test-error-stream)
 1869     (clear-stream $_test-error-buffered-file->buffer)
 1870     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1871     68/push 0/imm32
 1872     68/push 0/imm32
 1873     89/<- %edx 4/r32/esp
 1874     (tailor-exit-descriptor %edx 0x10)
 1875     #
 1876     (write _test-input-stream "fn f {\n")
 1877     (write _test-input-stream "  var x/eax: int <- g\n")
 1878     (write _test-input-stream "}\n")
 1879     (write _test-input-stream "fn g -> a/eax: foo {\n")
 1880     (write _test-input-stream "}\n")
 1881     # convert
 1882     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1883     # registers except esp clobbered at this point
 1884     # restore ed
 1885     89/<- %edx 4/r32/esp
 1886     (flush _test-output-buffered-file)
 1887     (flush _test-error-buffered-file)
 1888 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1894     # check output
 1895     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-output-type: output should be empty")
 1896     (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")
 1897     # check that stop(1) was called
 1898     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-output-type: exit status")
 1899     # don't restore from ebp
 1900     81 0/subop/add %esp 8/imm32
 1901     5d/pop-to-ebp
 1902     c3/return
 1903 
 1904 test-convert-function-call-with-too-few-outputs:
 1905     # . prologue
 1906     55/push-ebp
 1907     89/<- %ebp 4/r32/esp
 1908     # setup
 1909     (clear-stream _test-input-stream)
 1910     (clear-stream $_test-input-buffered-file->buffer)
 1911     (clear-stream _test-output-stream)
 1912     (clear-stream $_test-output-buffered-file->buffer)
 1913     (clear-stream _test-error-stream)
 1914     (clear-stream $_test-error-buffered-file->buffer)
 1915     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1916     68/push 0/imm32
 1917     68/push 0/imm32
 1918     89/<- %edx 4/r32/esp
 1919     (tailor-exit-descriptor %edx 0x10)
 1920     #
 1921     (write _test-input-stream "fn f {\n")
 1922     (write _test-input-stream "  g\n")
 1923     (write _test-input-stream "}\n")
 1924     (write _test-input-stream "fn g -> a/eax: int {\n")
 1925     (write _test-input-stream "}\n")
 1926     # convert
 1927     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1928     # registers except esp clobbered at this point
 1929     # restore ed
 1930     89/<- %edx 4/r32/esp
 1931     (flush _test-output-buffered-file)
 1932     (flush _test-error-buffered-file)
 1933 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1939     # check output
 1940     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-few-outputs: output should be empty")
 1941     (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")
 1942     # check that stop(1) was called
 1943     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-few-outputs: exit status")
 1944     # don't restore from ebp
 1945     81 0/subop/add %esp 8/imm32
 1946     5d/pop-to-ebp
 1947     c3/return
 1948 
 1949 test-convert-function-call-with-too-many-outputs:
 1950     # . prologue
 1951     55/push-ebp
 1952     89/<- %ebp 4/r32/esp
 1953     # setup
 1954     (clear-stream _test-input-stream)
 1955     (clear-stream $_test-input-buffered-file->buffer)
 1956     (clear-stream _test-output-stream)
 1957     (clear-stream $_test-output-buffered-file->buffer)
 1958     (clear-stream _test-error-stream)
 1959     (clear-stream $_test-error-buffered-file->buffer)
 1960     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1961     68/push 0/imm32
 1962     68/push 0/imm32
 1963     89/<- %edx 4/r32/esp
 1964     (tailor-exit-descriptor %edx 0x10)
 1965     #
 1966     (write _test-input-stream "fn f {\n")
 1967     (write _test-input-stream "  var x/eax: int <- g\n")
 1968     (write _test-input-stream "}\n")
 1969     (write _test-input-stream "fn g {\n")
 1970     (write _test-input-stream "}\n")
 1971     # convert
 1972     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1973     # registers except esp clobbered at this point
 1974     # restore ed
 1975     89/<- %edx 4/r32/esp
 1976     (flush _test-output-buffered-file)
 1977     (flush _test-error-buffered-file)
 1978 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1984     # check output
 1985     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-many-outputs: output should be empty")
 1986     (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")
 1987     # check that stop(1) was called
 1988     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-many-outputs: exit status")
 1989     # don't restore from ebp
 1990     81 0/subop/add %esp 8/imm32
 1991     5d/pop-to-ebp
 1992     c3/return
 1993 
 1994 test-convert-function-call-with-missing-output-register:
 1995     # . prologue
 1996     55/push-ebp
 1997     89/<- %ebp 4/r32/esp
 1998     # setup
 1999     (clear-stream _test-input-stream)
 2000     (clear-stream $_test-input-buffered-file->buffer)
 2001     (clear-stream _test-output-stream)
 2002     (clear-stream $_test-output-buffered-file->buffer)
 2003     (clear-stream _test-error-stream)
 2004     (clear-stream $_test-error-buffered-file->buffer)
 2005     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 2006     68/push 0/imm32
 2007     68/push 0/imm32
 2008     89/<- %edx 4/r32/esp
 2009     (tailor-exit-descriptor %edx 0x10)
 2010     #
 2011     (write _test-input-stream "fn f {\n")
 2012     (write _test-input-stream "  var x: int\n")
 2013     (write _test-input-stream "  x <- g\n")
 2014     (write _test-input-stream "}\n")
 2015     (write _test-input-stream "fn g -> a/eax: int {\n")
 2016     (write _test-input-stream "}\n")
 2017     # convert
 2018     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 2019     # registers except esp clobbered at this point
 2020     # restore ed
 2021     89/<- %edx 4/r32/esp
 2022     (flush _test-output-buffered-file)
 2023     (flush _test-error-buffered-file)
 2024 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2030     # check output
 2031     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-missing-output-register: output should be empty")
 2032     (check-next-stream-line-equal _test-error-stream  "fn f: call g: output 'x' is not in a register"  "F - test-convert-function-call-with-missing-output-register: error message")
 2033     # check that stop(1) was called
 2034     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-missing-output-register: exit status")
 2035     # don't restore from ebp
 2036     81 0/subop/add %esp 8/imm32
 2037     5d/pop-to-ebp
 2038     c3/return
 2039 
 2040 test-convert-function-call-with-incorrect-output-register:
 2041     # . prologue
 2042     55/push-ebp
 2043     89/<- %ebp 4/r32/esp
 2044     # setup
 2045     (clear-stream _test-input-stream)
 2046     (clear-stream $_test-input-buffered-file->buffer)
 2047     (clear-stream _test-output-stream)
 2048     (clear-stream $_test-output-buffered-file->buffer)
 2049     (clear-stream _test-error-stream)
 2050     (clear-stream $_test-error-buffered-file->buffer)
 2051     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 2052     68/push 0/imm32
 2053     68/push 0/imm32
 2054     89/<- %edx 4/r32/esp
 2055     (tailor-exit-descriptor %edx 0x10)
 2056     #
 2057     (write _test-input-stream "fn f {\n")
 2058     (write _test-input-stream "  var x/ecx: int <- g\n")
 2059     (write _test-input-stream "}\n")
 2060     (write _test-input-stream "fn g -> a/eax: int {\n")
 2061     (write _test-input-stream "}\n")
 2062     # convert
 2063     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 2064     # registers except esp clobbered at this point
 2065     # restore ed
 2066     89/<- %edx 4/r32/esp
 2067     (flush _test-output-buffered-file)
 2068     (flush _test-error-buffered-file)
 2069 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2075     # check output
 2076     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-output-register: output should be empty")
 2077     (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")
 2078     # check that stop(1) was called
 2079     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-output-register: exit status")
 2080     # don't restore from ebp
 2081     81 0/subop/add %esp 8/imm32
 2082     5d/pop-to-ebp
 2083     c3/return
 2084 
 2085 test-convert-function-with-local-var-dereferenced:
 2086     # . prologue
 2087     55/push-ebp
 2088     89/<- %ebp 4/r32/esp
 2089     # setup
 2090     (clear-stream _test-input-stream)
 2091     (clear-stream $_test-input-buffered-file->buffer)
 2092     (clear-stream _test-output-stream)
 2093     (clear-stream $_test-output-buffered-file->buffer)
 2094     #
 2095     (write _test-input-stream "fn foo {\n")
 2096     (write _test-input-stream "  var x/ecx: (addr int) <- copy 0\n")
 2097     (write _test-input-stream "  increment *x\n")
 2098     (write _test-input-stream "}\n")
 2099     # convert
 2100     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2101     (flush _test-output-buffered-file)
 2102 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2108     # check output
 2109     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-dereferenced/0")
 2110     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-dereferenced/1")
 2111     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-dereferenced/2")
 2112     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-dereferenced/3")
 2113     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-dereferenced/4")
 2114     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-dereferenced/5")
 2115     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-dereferenced/6")
 2116     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-local-var-dereferenced/7")
 2117     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *ecx"  "F - test-convert-function-with-local-var-dereferenced/8")
 2118     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-dereferenced/9")
 2119     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-dereferenced/10")
 2120     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-dereferenced/11")
 2121     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-dereferenced/12")
 2122     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-dereferenced/13")
 2123     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-dereferenced/14")
 2124     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-dereferenced/15")
 2125     # . epilogue
 2126     89/<- %esp 5/r32/ebp
 2127     5d/pop-to-ebp
 2128     c3/return
 2129 
 2130 # variables of type 'byte' are not allowed on the stack
 2131 test-convert-function-with-byte-operations:
 2132     # . prologue
 2133     55/push-ebp
 2134     89/<- %ebp 4/r32/esp
 2135     # setup
 2136     (clear-stream _test-input-stream)
 2137     (clear-stream $_test-input-buffered-file->buffer)
 2138     (clear-stream _test-output-stream)
 2139     (clear-stream $_test-output-buffered-file->buffer)
 2140     #
 2141     (write _test-input-stream "fn foo {\n")
 2142     (write _test-input-stream "  var x/eax: byte <- copy 0\n")
 2143     (write _test-input-stream "  var y/ecx: byte <- copy 0\n")
 2144     (write _test-input-stream "  y <- copy-byte x\n")
 2145     (write _test-input-stream "  var z/edx: (addr byte) <- copy 0\n")
 2146     (write _test-input-stream "  y <- copy-byte *z\n")
 2147     (write _test-input-stream "  copy-byte-to *z, x\n")
 2148     (write _test-input-stream "}\n")
 2149     # convert
 2150     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2151     (flush _test-output-buffered-file)
 2152 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2158     # check output
 2159     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-function-with-byte-operations/0")
 2160     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-function-with-byte-operations/1")
 2161     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-function-with-byte-operations/2")
 2162     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-function-with-byte-operations/3")
 2163     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-function-with-byte-operations/4")
 2164     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-function-with-byte-operations/5")
 2165     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-function-with-byte-operations/6")
 2166     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-function-with-byte-operations/7")
 2167     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-function-with-byte-operations/8")
 2168     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"                  "F - test-convert-function-with-byte-operations/9")
 2169     (check-next-stream-line-equal _test-output-stream "    8a/byte-> %eax 0x00000001/r32"           "F - test-convert-function-with-byte-operations/10")
 2170     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %edx"                    "F - test-convert-function-with-byte-operations/11")
 2171     (check-next-stream-line-equal _test-output-stream "    ba/copy-to-edx 0/imm32"                  "F - test-convert-function-with-byte-operations/12")
 2172     (check-next-stream-line-equal _test-output-stream "    8a/byte-> *edx 0x00000001/r32"           "F - test-convert-function-with-byte-operations/13")
 2173     (check-next-stream-line-equal _test-output-stream "    88/byte<- *edx 0x00000000/r32"           "F - test-convert-function-with-byte-operations/14")
 2174     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %edx"                     "F - test-convert-function-with-byte-operations/15")
 2175     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-function-with-byte-operations/16")
 2176     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-function-with-byte-operations/17")
 2177     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-function-with-byte-operations/18")
 2178     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-function-with-byte-operations/19")
 2179     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-function-with-byte-operations/20")
 2180     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-function-with-byte-operations/21")
 2181     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-function-with-byte-operations/22")
 2182     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-function-with-byte-operations/23")
 2183     # . epilogue
 2184     89/<- %esp 5/r32/ebp
 2185     5d/pop-to-ebp
 2186     c3/return
 2187 
 2188 # variables of type 'byte' _can_ be function args. They then occupy 4 bytes.
 2189 test-copy-byte-var-from-fn-arg:
 2190     # . prologue
 2191     55/push-ebp
 2192     89/<- %ebp 4/r32/esp
 2193     # setup
 2194     (clear-stream _test-input-stream)
 2195     (clear-stream $_test-input-buffered-file->buffer)
 2196     (clear-stream _test-output-stream)
 2197     (clear-stream $_test-output-buffered-file->buffer)
 2198     #
 2199     (write _test-input-stream "fn foo x: byte, y: int {\n")
 2200     (write _test-input-stream "  var a/eax: byte <- copy x\n")
 2201     (write _test-input-stream "  var b/eax: int <- copy y\n")
 2202     (write _test-input-stream "}\n")
 2203     # convert
 2204     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2205     (flush _test-output-buffered-file)
 2206 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2212     # check output
 2213     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-copy-byte-from-fn-arg/0")
 2214     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-copy-byte-from-fn-arg/1")
 2215     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-copy-byte-from-fn-arg/2")
 2216     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-copy-byte-from-fn-arg/3")
 2217     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-copy-byte-from-fn-arg/4")
 2218     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-copy-byte-from-fn-arg/5")
 2219     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-copy-byte-from-fn-arg/6")
 2220     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-copy-byte-from-fn-arg/7")
 2221     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x0000000c) 0x00000000/r32"  "F - test-copy-byte-from-fn-arg/8")
 2222     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"   "F - test-copy-byte-from-fn-arg/9")
 2223     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-copy-byte-from-fn-arg/10")
 2224     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-copy-byte-from-fn-arg/11")
 2225     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-copy-byte-from-fn-arg/12")
 2226     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-copy-byte-from-fn-arg/13")
 2227     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-copy-byte-from-fn-arg/14")
 2228     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-copy-byte-from-fn-arg/15")
 2229     # . epilogue
 2230     89/<- %esp 5/r32/ebp
 2231     5d/pop-to-ebp
 2232     c3/return
 2233 
 2234 test-convert-compare-register-with-literal:
 2235     # . prologue
 2236     55/push-ebp
 2237     89/<- %ebp 4/r32/esp
 2238     # setup
 2239     (clear-stream _test-input-stream)
 2240     (clear-stream $_test-input-buffered-file->buffer)
 2241     (clear-stream _test-output-stream)
 2242     (clear-stream $_test-output-buffered-file->buffer)
 2243     #
 2244     (write _test-input-stream "fn foo {\n")
 2245     (write _test-input-stream "  var x/ecx: int <- copy 0\n")
 2246     (write _test-input-stream "  compare x, 0\n")
 2247     (write _test-input-stream "}\n")
 2248     # convert
 2249     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2250     (flush _test-output-buffered-file)
 2251 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2257     # check output
 2258     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-compare-register-with-literal/0")
 2259     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-compare-register-with-literal/1")
 2260     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-compare-register-with-literal/2")
 2261     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-compare-register-with-literal/3")
 2262     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-compare-register-with-literal/4")
 2263     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-compare-register-with-literal/5")
 2264     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
 2265     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-compare-register-with-literal/7")
 2266     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %ecx 0/imm32"  "F - test-convert-compare-register-with-literal/8")
 2267     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
 2268     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-compare-register-with-literal/10")
 2269     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-compare-register-with-literal/11")
 2270     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-compare-register-with-literal/12")
 2271     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-compare-register-with-literal/13")
 2272     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-compare-register-with-literal/14")
 2273     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-compare-register-with-literal/15")
 2274     # . epilogue
 2275     89/<- %esp 5/r32/ebp
 2276     5d/pop-to-ebp
 2277     c3/return
 2278 
 2279 test-unknown-variable:
 2280     # . prologue
 2281     55/push-ebp
 2282     89/<- %ebp 4/r32/esp
 2283     # setup
 2284     (clear-stream _test-input-stream)
 2285     (clear-stream $_test-input-buffered-file->buffer)
 2286     (clear-stream _test-output-stream)
 2287     (clear-stream $_test-output-buffered-file->buffer)
 2288     (clear-stream _test-error-stream)
 2289     (clear-stream $_test-error-buffered-file->buffer)
 2290     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 2291     68/push 0/imm32
 2292     68/push 0/imm32
 2293     89/<- %edx 4/r32/esp
 2294     (tailor-exit-descriptor %edx 0x10)
 2295     #
 2296     (write _test-input-stream "fn foo {\n")
 2297     (write _test-input-stream "  compare x, 0\n")
 2298     (write _test-input-stream "}\n")
 2299     # convert
 2300     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 2301     # registers except esp clobbered at this point
 2302     # restore ed
 2303     89/<- %edx 4/r32/esp
 2304     (flush _test-output-buffered-file)
 2305     (flush _test-error-buffered-file)
 2306 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2312     # check output
 2313     (check-stream-equal _test-output-stream  ""  "F - test-unknown-variable: output should be empty")
 2314     (check-next-stream-line-equal _test-error-stream  "fn foo: unknown variable 'x'"  "F - test-unknown-variable: error message")
 2315     # check that stop(1) was called
 2316     (check-ints-equal *(edx+4) 2 "F - test-unknown-variable: exit status")
 2317     # don't restore from ebp
 2318     81 0/subop/add %esp 8/imm32
 2319     # . epilogue
 2320     5d/pop-to-ebp
 2321     c3/return
 2322 
 2323 test-convert-function-with-local-var-in-block:
 2324     # . prologue
 2325     55/push-ebp
 2326     89/<- %ebp 4/r32/esp
 2327     # setup
 2328     (clear-stream _test-input-stream)
 2329     (clear-stream $_test-input-buffered-file->buffer)
 2330     (clear-stream _test-output-stream)
 2331     (clear-stream $_test-output-buffered-file->buffer)
 2332     #
 2333     (write _test-input-stream "fn foo {\n")
 2334     (write _test-input-stream "  {\n")
 2335     (write _test-input-stream "    var x: int\n")
 2336     (write _test-input-stream "    increment x\n")
 2337     (write _test-input-stream "  }\n")
 2338     (write _test-input-stream "}\n")
 2339     # convert
 2340     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2341     (flush _test-output-buffered-file)
 2342 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2348     # check output
 2349     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-block/0")
 2350     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-block/1")
 2351     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-block/2")
 2352     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-block/3")
 2353     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-block/4")
 2354     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-block/5")
 2355     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-block/6")
 2356     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-local-var-in-block/7")
 2357     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-block/8")
 2358     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-block/9")
 2359     (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")
 2360     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-block/11")
 2361     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-local-var-in-block/12")
 2362     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-block/13")
 2363     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-block/14")
 2364     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-block/15")
 2365     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-block/16")
 2366     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-block/17")
 2367     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-block/18")
 2368     # . epilogue
 2369     89/<- %esp 5/r32/ebp
 2370     5d/pop-to-ebp
 2371     c3/return
 2372 
 2373 test-convert-function-with-local-var-in-mem-after-block:
 2374     # . prologue
 2375     55/push-ebp
 2376     89/<- %ebp 4/r32/esp
 2377     # setup
 2378     (clear-stream _test-input-stream)
 2379     (clear-stream $_test-input-buffered-file->buffer)
 2380     (clear-stream _test-output-stream)
 2381     (clear-stream $_test-output-buffered-file->buffer)
 2382     #
 2383     (write _test-input-stream "fn foo {\n")
 2384     (write _test-input-stream "  {\n")
 2385     (write _test-input-stream "    var y: int\n")
 2386     (write _test-input-stream "  }\n")
 2387     (write _test-input-stream "  var x: int\n")
 2388     (write _test-input-stream "  increment x\n")
 2389     (write _test-input-stream "}\n")
 2390     # convert
 2391     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2392     (flush _test-output-buffered-file)
 2393 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2399     # check output
 2400     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-mem-after-block/0")
 2401     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-mem-after-block/1")
 2402     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-mem-after-block/2")
 2403     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-mem-after-block/3")
 2404     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-mem-after-block/4")
 2405     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-mem-after-block/5")
 2406     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-mem-after-block/6")
 2407     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-local-var-in-mem-after-block/7")
 2408     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-mem-after-block/8")
 2409     (check-next-stream-line-equal _test-output-stream "      81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-local-var-in-mem-after-block/9")
 2410     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-mem-after-block/10")
 2411     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-local-var-in-mem-after-block/11")
 2412     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-in-mem-after-block/12")
 2413     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-mem-after-block/13")
 2414     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-local-var-in-mem-after-block/14")
 2415     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-mem-after-block/15")
 2416     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-mem-after-block/16")
 2417     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-mem-after-block/17")
 2418     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-mem-after-block/18")
 2419     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-mem-after-block/19")
 2420     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-mem-after-block/20")
 2421     # . epilogue
 2422     89/<- %esp 5/r32/ebp
 2423     5d/pop-to-ebp
 2424     c3/return
 2425 
 2426 test-convert-function-with-local-var-in-named-block:
 2427     # . prologue
 2428     55/push-ebp
 2429     89/<- %ebp 4/r32/esp
 2430     # setup
 2431     (clear-stream _test-input-stream)
 2432     (clear-stream $_test-input-buffered-file->buffer)
 2433     (clear-stream _test-output-stream)
 2434     (clear-stream $_test-output-buffered-file->buffer)
 2435     #
 2436     (write _test-input-stream "fn foo {\n")
 2437     (write _test-input-stream "  $bar: {\n")
 2438     (write _test-input-stream "    var x: int\n")
 2439     (write _test-input-stream "    increment x\n")
 2440     (write _test-input-stream "  }\n")
 2441     (write _test-input-stream "}\n")
 2442     # convert
 2443     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2444     (flush _test-output-buffered-file)
 2445 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2451     # check output
 2452     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-named-block/0")
 2453     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-named-block/1")
 2454     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-named-block/2")
 2455     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-named-block/3")
 2456     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-named-block/4")
 2457     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-named-block/5")
 2458     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-named-block/6")
 2459     (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-local-var-in-named-block/7")
 2460     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-named-block/8")
 2461     (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")
 2462     (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")
 2463     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-named-block/11")
 2464     (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-local-var-in-named-block/12")
 2465     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-named-block/13")
 2466     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-named-block/14")
 2467     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-named-block/15")
 2468     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-named-block/16")
 2469     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-named-block/17")
 2470     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-named-block/18")
 2471     # . epilogue
 2472     89/<- %esp 5/r32/ebp
 2473     5d/pop-to-ebp
 2474     c3/return
 2475 
 2476 test-unknown-variable-in-named-block:
 2477     # . prologue
 2478     55/push-ebp
 2479     89/<- %ebp 4/r32/esp
 2480     # setup
 2481     (clear-stream _test-input-stream)
 2482     (clear-stream $_test-input-buffered-file->buffer)
 2483     (clear-stream _test-output-stream)
 2484     (clear-stream $_test-output-buffered-file->buffer)
 2485     (clear-stream _test-error-stream)
 2486     (clear-stream $_test-error-buffered-file->buffer)
 2487     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 2488     68/push 0/imm32
 2489     68/push 0/imm32
 2490     89/<- %edx 4/r32/esp
 2491     (tailor-exit-descriptor %edx 0x10)
 2492     #
 2493     (write _test-input-stream "fn foo {\n")
 2494     (write _test-input-stream "  $a: {\n")
 2495     (write _test-input-stream "    compare x, 0\n")
 2496     (write _test-input-stream "  }\n")
 2497     (write _test-input-stream "}\n")
 2498     # convert
 2499     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 2500     # registers except esp clobbered at this point
 2501     # restore ed
 2502     89/<- %edx 4/r32/esp
 2503     (flush _test-output-buffered-file)
 2504     (flush _test-error-buffered-file)
 2505 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2511     # check output
 2512     (check-stream-equal _test-output-stream  ""  "F - test-unknown-variable-in-named-block: output should be empty")
 2513     (check-next-stream-line-equal _test-error-stream  "fn foo: unknown variable 'x'"  "F - test-unknown-variable-in-named-block: error message")
 2514     # check that stop(1) was called
 2515     (check-ints-equal *(edx+4) 2 "F - test-unknown-variable-in-named-block: exit status")
 2516     # don't restore from ebp
 2517     81 0/subop/add %esp 8/imm32
 2518     # . epilogue
 2519     5d/pop-to-ebp
 2520     c3/return
 2521 
 2522 test-always-shadow-outermost-reg-vars-in-function:
 2523     # . prologue
 2524     55/push-ebp
 2525     89/<- %ebp 4/r32/esp
 2526     # setup
 2527     (clear-stream _test-input-stream)
 2528     (clear-stream $_test-input-buffered-file->buffer)
 2529     (clear-stream _test-output-stream)
 2530     (clear-stream $_test-output-buffered-file->buffer)
 2531     #
 2532     (write _test-input-stream "fn foo {\n")
 2533     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2534     (write _test-input-stream "}\n")
 2535     # convert
 2536     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2537     (flush _test-output-buffered-file)
 2538 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2544     # check output
 2545     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-always-shadow-outermost-reg-vars-in-function/0")
 2546     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-always-shadow-outermost-reg-vars-in-function/1")
 2547     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-always-shadow-outermost-reg-vars-in-function/2")
 2548     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-always-shadow-outermost-reg-vars-in-function/3")
 2549     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-always-shadow-outermost-reg-vars-in-function/4")
 2550     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-always-shadow-outermost-reg-vars-in-function/5")
 2551     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
 2552     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-always-shadow-outermost-reg-vars-in-function/8")
 2553     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
 2554     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-always-shadow-outermost-reg-vars-in-function/12")
 2555     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-always-shadow-outermost-reg-vars-in-function/13")
 2556     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-always-shadow-outermost-reg-vars-in-function/14")
 2557     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-always-shadow-outermost-reg-vars-in-function/15")
 2558     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-always-shadow-outermost-reg-vars-in-function/16")
 2559     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-always-shadow-outermost-reg-vars-in-function/17")
 2560     # . epilogue
 2561     89/<- %esp 5/r32/ebp
 2562     5d/pop-to-ebp
 2563     c3/return
 2564 
 2565 _pending-test-clobber-dead-local:
 2566     # . prologue
 2567     55/push-ebp
 2568     89/<- %ebp 4/r32/esp
 2569     # setup
 2570     (clear-stream _test-input-stream)
 2571     (clear-stream $_test-input-buffered-file->buffer)
 2572     (clear-stream _test-output-stream)
 2573     (clear-stream $_test-output-buffered-file->buffer)
 2574     #
 2575     (write _test-input-stream "fn foo {\n")
 2576     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2577     (write _test-input-stream "  {\n")
 2578     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 2579     (write _test-input-stream "  }\n")
 2580     (write _test-input-stream "}\n")
 2581     # convert
 2582     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2583     (flush _test-output-buffered-file)
 2584 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2590     # check output
 2591     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-clobber-dead-local/0")
 2592     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-clobber-dead-local/1")
 2593     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-clobber-dead-local/2")
 2594     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-clobber-dead-local/3")
 2595     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-clobber-dead-local/4")
 2596     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-clobber-dead-local/5")
 2597     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-clobber-dead-local/6")
 2598     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-clobber-dead-local/7")
 2599     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-clobber-dead-local/8")
 2600     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-clobber-dead-local/9")
 2601     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-clobber-dead-local/10")  # no push/pop here
 2602     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-clobber-dead-local/11")
 2603     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-clobber-dead-local/12")
 2604     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-clobber-dead-local/13")
 2605     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-clobber-dead-local/14")
 2606     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-clobber-dead-local/15")
 2607     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-clobber-dead-local/16")
 2608     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-clobber-dead-local/17")
 2609     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-clobber-dead-local/18")
 2610     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-clobber-dead-local/19")
 2611     # . epilogue
 2612     89/<- %esp 5/r32/ebp
 2613     5d/pop-to-ebp
 2614     c3/return
 2615 
 2616 test-shadow-live-local:
 2617     # . prologue
 2618     55/push-ebp
 2619     89/<- %ebp 4/r32/esp
 2620     # setup
 2621     (clear-stream _test-input-stream)
 2622     (clear-stream $_test-input-buffered-file->buffer)
 2623     (clear-stream _test-output-stream)
 2624     (clear-stream $_test-output-buffered-file->buffer)
 2625     #
 2626     (write _test-input-stream "fn foo {\n")
 2627     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2628     (write _test-input-stream "  {\n")
 2629     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 2630     (write _test-input-stream "  }\n")
 2631     (write _test-input-stream "  x <- increment\n")
 2632     (write _test-input-stream "}\n")
 2633     # convert
 2634     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2635     (flush _test-output-buffered-file)
 2636 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2642     # check output
 2643     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-live-local/0")
 2644     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-live-local/1")
 2645     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-live-local/2")
 2646     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-live-local/3")
 2647     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-live-local/4")
 2648     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-live-local/5")
 2649     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-live-local/6")
 2650     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-live-local/7")
 2651     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-live-local/8")
 2652     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-live-local/9")
 2653     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-live-local/10")
 2654     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-live-local/11")
 2655     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-live-local/12")
 2656     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-live-local/13")
 2657     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-live-local/14")
 2658     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-live-local/15")
 2659     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-live-local/16")
 2660     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-live-local/17")
 2661     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-live-local/18")
 2662     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-live-local/19")
 2663     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-live-local/20")
 2664     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-live-local/21")
 2665     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-live-local/22")
 2666     # . epilogue
 2667     89/<- %esp 5/r32/ebp
 2668     5d/pop-to-ebp
 2669     c3/return
 2670 
 2671 test-shadow-name:
 2672     # . prologue
 2673     55/push-ebp
 2674     89/<- %ebp 4/r32/esp
 2675     # setup
 2676     (clear-stream _test-input-stream)
 2677     (clear-stream $_test-input-buffered-file->buffer)
 2678     (clear-stream _test-output-stream)
 2679     (clear-stream $_test-output-buffered-file->buffer)
 2680     #
 2681     (write _test-input-stream "fn foo {\n")
 2682     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2683     (write _test-input-stream "  {\n")
 2684     (write _test-input-stream "    var x/edx: int <- copy 4\n")
 2685     (write _test-input-stream "  }\n")
 2686     (write _test-input-stream "  x <- increment\n")
 2687     (write _test-input-stream "}\n")
 2688     # convert
 2689     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2690     (flush _test-output-buffered-file)
 2691 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2697     # check output
 2698     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-name/0")
 2699     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-name/1")
 2700     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-name/2")
 2701     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-name/3")
 2702     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-name/4")
 2703     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-name/5")
 2704     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-name/6")
 2705     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-name/7")
 2706     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-name/8")
 2707     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-name/9")
 2708     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %edx"  "F - test-shadow-name/10")
 2709     (check-next-stream-line-equal _test-output-stream "      ba/copy-to-edx 4/imm32"  "F - test-shadow-name/11")
 2710     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %edx" "F - test-shadow-name/12")
 2711     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-name/13")
 2712     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-name/14")
 2713     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-name/15")
 2714     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-name/16")
 2715     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-name/17")
 2716     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-name/18")
 2717     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-name/19")
 2718     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-name/20")
 2719     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-name/21")
 2720     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-name/22")
 2721     # . epilogue
 2722     89/<- %esp 5/r32/ebp
 2723     5d/pop-to-ebp
 2724     c3/return
 2725 
 2726 test-shadow-name-2:
 2727     # . prologue
 2728     55/push-ebp
 2729     89/<- %ebp 4/r32/esp
 2730     # setup
 2731     (clear-stream _test-input-stream)
 2732     (clear-stream $_test-input-buffered-file->buffer)
 2733     (clear-stream _test-output-stream)
 2734     (clear-stream $_test-output-buffered-file->buffer)
 2735     #
 2736     (write _test-input-stream "fn foo {\n")
 2737     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2738     (write _test-input-stream "  {\n")
 2739     (write _test-input-stream "    var x/edx: int <- copy 4\n")
 2740     (write _test-input-stream "    var y/ecx: int <- copy 5\n")
 2741     (write _test-input-stream "  }\n")
 2742     (write _test-input-stream "  x <- increment\n")
 2743     (write _test-input-stream "}\n")
 2744     # convert
 2745     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2746     (flush _test-output-buffered-file)
 2747 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2753     # check output
 2754     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-name-2/0")
 2755     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-name-2/1")
 2756     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-name-2/2")
 2757     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-name-2/3")
 2758     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-name-2/4")
 2759     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-name-2/5")
 2760     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-name-2/6")
 2761     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-name-2/7")
 2762     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-name-2/8")
 2763     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-name-2/9")
 2764     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %edx"  "F - test-shadow-name-2/10")
 2765     (check-next-stream-line-equal _test-output-stream "      ba/copy-to-edx 4/imm32"  "F - test-shadow-name-2/11")
 2766     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-name-2/12")
 2767     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 5/imm32"  "F - test-shadow-name-2/13")
 2768     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-name-2/14")
 2769     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %edx" "F - test-shadow-name-2/15")
 2770     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-name-2/16")
 2771     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-name-2/17")
 2772     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-name-2/18")
 2773     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-name-2/19")
 2774     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-name-2/20")
 2775     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-name-2/21")
 2776     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-name-2/22")
 2777     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-name-2/23")
 2778     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-name-2/24")
 2779     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-name-2/25")
 2780     # . epilogue
 2781     89/<- %esp 5/r32/ebp
 2782     5d/pop-to-ebp
 2783     c3/return
 2784 
 2785 test-do-not-spill-same-register-in-block:
 2786     # . prologue
 2787     55/push-ebp
 2788     89/<- %ebp 4/r32/esp
 2789     # setup
 2790     (clear-stream _test-input-stream)
 2791     (clear-stream $_test-input-buffered-file->buffer)
 2792     (clear-stream _test-output-stream)
 2793     (clear-stream $_test-output-buffered-file->buffer)
 2794     #
 2795     (write _test-input-stream "fn foo {\n")
 2796     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2797     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2798     (write _test-input-stream "  y <- increment\n")
 2799     (write _test-input-stream "}\n")
 2800     # convert
 2801     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2802     (flush _test-output-buffered-file)
 2803 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2809     # check output
 2810     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-do-not-spill-same-register-in-block/0")
 2811     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-do-not-spill-same-register-in-block/1")
 2812     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-do-not-spill-same-register-in-block/2")
 2813     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-do-not-spill-same-register-in-block/3")
 2814     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-do-not-spill-same-register-in-block/4")
 2815     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-do-not-spill-same-register-in-block/5")
 2816     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-do-not-spill-same-register-in-block/6")
 2817     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-do-not-spill-same-register-in-block/7")
 2818     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-do-not-spill-same-register-in-block/8")
 2819     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-do-not-spill-same-register-in-block/9")
 2820     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-do-not-spill-same-register-in-block/10")
 2821     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-do-not-spill-same-register-in-block/11")
 2822     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-do-not-spill-same-register-in-block/12")
 2823     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-do-not-spill-same-register-in-block/13")
 2824     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-do-not-spill-same-register-in-block/14")
 2825     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-do-not-spill-same-register-in-block/15")
 2826     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-do-not-spill-same-register-in-block/16")
 2827     # . epilogue
 2828     89/<- %esp 5/r32/ebp
 2829     5d/pop-to-ebp
 2830     c3/return
 2831 
 2832 test-spill-different-register-in-block:
 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     #
 2842     (write _test-input-stream "fn foo {\n")
 2843     (write _test-input-stream "  var x/eax: int <- copy 3\n")
 2844     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2845     (write _test-input-stream "  y <- increment\n")
 2846     (write _test-input-stream "}\n")
 2847     # convert
 2848     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2849     (flush _test-output-buffered-file)
 2850 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2856     # check output
 2857     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-spill-different-register-in-block/0")
 2858     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-spill-different-register-in-block/1")
 2859     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-spill-different-register-in-block/2")
 2860     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-spill-different-register-in-block/3")
 2861     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-spill-different-register-in-block/4")
 2862     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-spill-different-register-in-block/5")
 2863     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-spill-different-register-in-block/6")
 2864     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-spill-different-register-in-block/7")
 2865     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-spill-different-register-in-block/8")
 2866     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-spill-different-register-in-block/9")
 2867     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-spill-different-register-in-block/10")
 2868     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-spill-different-register-in-block/11")
 2869     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-spill-different-register-in-block/12")
 2870     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-spill-different-register-in-block/13")
 2871     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-spill-different-register-in-block/14")
 2872     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-spill-different-register-in-block/15")
 2873     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-spill-different-register-in-block/16")
 2874     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-spill-different-register-in-block/17")
 2875     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-spill-different-register-in-block/18")
 2876     # . epilogue
 2877     89/<- %esp 5/r32/ebp
 2878     5d/pop-to-ebp
 2879     c3/return
 2880 
 2881 test-shadow-live-output:
 2882     # . prologue
 2883     55/push-ebp
 2884     89/<- %ebp 4/r32/esp
 2885     # setup
 2886     (clear-stream _test-input-stream)
 2887     (clear-stream $_test-input-buffered-file->buffer)
 2888     (clear-stream _test-output-stream)
 2889     (clear-stream $_test-output-buffered-file->buffer)
 2890     #
 2891     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2892     (write _test-input-stream "  x <- copy 3\n")
 2893     (write _test-input-stream "  {\n")
 2894     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 2895     (write _test-input-stream "  }\n")
 2896     (write _test-input-stream "  x <- increment\n")
 2897     (write _test-input-stream "}\n")
 2898     # convert
 2899     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2900     (flush _test-output-buffered-file)
 2901 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2907     # check output
 2908     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-live-output/0")
 2909     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-live-output/1")
 2910     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-live-output/2")
 2911     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-live-output/3")
 2912     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-live-output/4")
 2913     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-live-output/5")
 2914     (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
 2915     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-live-output/8")
 2916     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-live-output/9")
 2917     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-live-output/10")
 2918     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-live-output/11")
 2919     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-live-output/12")
 2920     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-live-output/13")
 2921     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-live-output/14")
 2922     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-live-output/15")
 2923     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-live-output/17")
 2924     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-live-output/18")
 2925     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-live-output/19")
 2926     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-live-output/20")
 2927     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-live-output/21")
 2928     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-live-output/21")
 2929     # . epilogue
 2930     89/<- %esp 5/r32/ebp
 2931     5d/pop-to-ebp
 2932     c3/return
 2933 
 2934 test-stmt-defines-output-in-same-register-as-inout:
 2935     # . prologue
 2936     55/push-ebp
 2937     89/<- %ebp 4/r32/esp
 2938     # setup
 2939     (clear-stream _test-input-stream)
 2940     (clear-stream $_test-input-buffered-file->buffer)
 2941     (clear-stream _test-output-stream)
 2942     (clear-stream $_test-output-buffered-file->buffer)
 2943     (clear-stream _test-error-stream)
 2944     (clear-stream $_test-error-buffered-file->buffer)
 2945     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 2946     68/push 0/imm32
 2947     68/push 0/imm32
 2948     89/<- %edx 4/r32/esp
 2949     (tailor-exit-descriptor %edx 0x10)
 2950     #
 2951     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2952     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2953     (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
 2954     (write _test-input-stream "}\n")
 2955     # convert
 2956     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 2957     # registers except esp clobbered at this point
 2958     # restore ed
 2959     89/<- %edx 4/r32/esp
 2960     (flush _test-output-buffered-file)
 2961     (flush _test-error-buffered-file)
 2962 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2968     # no error; we looked up 'y' correctly before pushing the binding for 'x'
 2969     (check-stream-equal _test-error-stream  ""  "F - test-stmt-defines-output-in-same-register-as-inout: error stream should be empty")
 2970     # don't bother checking the generated code; that's in the test 'test-local-clobbered-by-fn-output' below
 2971     # don't restore from ebp
 2972     81 0/subop/add %esp 8/imm32
 2973     # . epilogue
 2974     5d/pop-to-ebp
 2975     c3/return
 2976 
 2977 test-local-clobbered-by-fn-output:
 2978     # . prologue
 2979     55/push-ebp
 2980     89/<- %ebp 4/r32/esp
 2981     # setup
 2982     (clear-stream _test-input-stream)
 2983     (clear-stream $_test-input-buffered-file->buffer)
 2984     (clear-stream _test-output-stream)
 2985     (clear-stream $_test-output-buffered-file->buffer)
 2986     #
 2987     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2988     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2989     (write _test-input-stream "  x <- copy y\n")
 2990     (write _test-input-stream "}\n")
 2991     # convert
 2992     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2993     (flush _test-output-buffered-file)
 2994 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3000     # check output
 3001     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-local-clobbered-by-fn-output/0")
 3002     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-local-clobbered-by-fn-output/1")
 3003     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-local-clobbered-by-fn-output/2")
 3004     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-local-clobbered-by-fn-output/3")
 3005     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-local-clobbered-by-fn-output/4")
 3006     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-local-clobbered-by-fn-output/5")
 3007     (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
 3008     (check-next-stream-line-equal _test-output-stream "    89/<- %ecx 0x00000001/r32"  "F - test-local-clobbered-by-fn-output/7")
 3009     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-local-clobbered-by-fn-output/8")
 3010     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-local-clobbered-by-fn-output/9")
 3011     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-local-clobbered-by-fn-output/10")
 3012     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-local-clobbered-by-fn-output/11")
 3013     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-local-clobbered-by-fn-output/12")
 3014     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-local-clobbered-by-fn-output/13")
 3015     # . epilogue
 3016     89/<- %esp 5/r32/ebp
 3017     5d/pop-to-ebp
 3018     c3/return
 3019 
 3020 test-read-output:
 3021     # . prologue
 3022     55/push-ebp
 3023     89/<- %ebp 4/r32/esp
 3024     # setup
 3025     (clear-stream _test-input-stream)
 3026     (clear-stream $_test-input-buffered-file->buffer)
 3027     (clear-stream _test-output-stream)
 3028     (clear-stream $_test-output-buffered-file->buffer)
 3029     #
 3030     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 3031     (write _test-input-stream "  x <- copy 0x34\n")
 3032     (write _test-input-stream "  compare x, 0x35\n")
 3033     (write _test-input-stream "}\n")
 3034     # convert
 3035     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3036     (flush _test-output-buffered-file)
 3037 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3043     # check output
 3044     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-read-output/0")
 3045     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-read-output/1")
 3046     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-read-output/2")
 3047     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-read-output/3")
 3048     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-read-output/4")
 3049     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-read-output/5")
 3050     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0x34/imm32"  "F - test-read-output/6")
 3051     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %ecx 0x35/imm32"  "F - test-read-output/7")
 3052     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-read-output/8")
 3053     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-read-output/9")
 3054     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-read-output/10")
 3055     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-read-output/11")
 3056     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-read-output/12")
 3057     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-read-output/13")
 3058     # . epilogue
 3059     89/<- %esp 5/r32/ebp
 3060     5d/pop-to-ebp
 3061     c3/return
 3062 
 3063 test-fn-output-written-in-inner-block:
 3064     # . prologue
 3065     55/push-ebp
 3066     89/<- %ebp 4/r32/esp
 3067     # setup
 3068     (clear-stream _test-input-stream)
 3069     (clear-stream $_test-input-buffered-file->buffer)
 3070     (clear-stream _test-output-stream)
 3071     (clear-stream $_test-output-buffered-file->buffer)
 3072     #
 3073     (write _test-input-stream "fn foo -> out/edi: int {\n")
 3074     (write _test-input-stream "  var a/eax: int <- copy 3\n")  # define outer local
 3075     (write _test-input-stream "  {\n")
 3076     (write _test-input-stream "    var a/ecx: int <- copy 4\n")  # shadow outer local
 3077     (write _test-input-stream "    out <- copy a\n")  # write to fn output
 3078     (write _test-input-stream "  }\n")
 3079     (write _test-input-stream "  compare a, 0\n")  # use outer local
 3080     (write _test-input-stream "}\n")
 3081     # convert
 3082     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3083     (flush _test-output-buffered-file)
 3084 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3090     # no error; defining 'out' didn't interfere with the reclamation of 'b'
 3091     # check output
 3092     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-fn-output-written-in-inner-block/0")
 3093     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-fn-output-written-in-inner-block/1")
 3094     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-fn-output-written-in-inner-block/2")
 3095     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-fn-output-written-in-inner-block/3")
 3096     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-fn-output-written-in-inner-block/4")
 3097     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-fn-output-written-in-inner-block/5")
 3098     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-fn-output-written-in-inner-block/6")
 3099     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-fn-output-written-in-inner-block/7")
 3100     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-fn-output-written-in-inner-block/8")
 3101     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-fn-output-written-in-inner-block/9")
 3102     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-fn-output-written-in-inner-block/10")
 3103     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-fn-output-written-in-inner-block/10")
 3104     (check-next-stream-line-equal _test-output-stream "      89/<- %edi 0x00000001/r32"  "F - test-fn-output-written-in-inner-block/11")
 3105     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx"  "F - test-fn-output-written-in-inner-block/12")
 3106     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-fn-output-written-in-inner-block/13")
 3107     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-fn-output-written-in-inner-block/14")
 3108     (check-next-stream-line-equal _test-output-stream "    3d/compare-eax-with 0/imm32"  "F - test-fn-output-written-in-inner-block/15")
 3109     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-fn-output-written-in-inner-block/16")
 3110     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-fn-output-written-in-inner-block/17")
 3111     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-fn-output-written-in-inner-block/18")
 3112     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-fn-output-written-in-inner-block/19")
 3113     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-fn-output-written-in-inner-block/20")
 3114     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-fn-output-written-in-inner-block/21")
 3115     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-fn-output-written-in-inner-block/22")
 3116     # . epilogue
 3117     89/<- %esp 5/r32/ebp
 3118     5d/pop-to-ebp
 3119     c3/return
 3120 
 3121 test-convert-function-with-branches-in-block:
 3122     # . prologue
 3123     55/push-ebp
 3124     89/<- %ebp 4/r32/esp
 3125     # setup
 3126     (clear-stream _test-input-stream)
 3127     (clear-stream $_test-input-buffered-file->buffer)
 3128     (clear-stream _test-output-stream)
 3129     (clear-stream $_test-output-buffered-file->buffer)
 3130     #
 3131     (write _test-input-stream "fn foo x: int {\n")
 3132     (write _test-input-stream "  {\n")
 3133     (write _test-input-stream "    break-if->=\n")
 3134     (write _test-input-stream "    loop-if-addr<\n")
 3135     (write _test-input-stream "    increment x\n")
 3136     (write _test-input-stream "    loop\n")
 3137     (write _test-input-stream "  }\n")
 3138     (write _test-input-stream "}\n")
 3139     # convert
 3140     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3141     (flush _test-output-buffered-file)
 3142 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3148     # check output
 3149     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-block/0")
 3150     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-block/1")
 3151     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-block/2")
 3152     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-block/3")
 3153     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-block/4")
 3154     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-block/5")
 3155     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-block/6")
 3156     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-in-block/7")
 3157     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/8")
 3158     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-block/9")
 3159     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-in-block/10")
 3160     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/11")
 3161     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/12")
 3162     (check-next-stream-line-equal _test-output-stream "        0f 83/jump-if-addr>= break/disp32"  "F - test-convert-function-with-branches-in-block/13")
 3163     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:loop/disp32"  "F - test-convert-function-with-branches-in-block/14")
 3164     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/15")
 3165     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-block/16")
 3166     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-in-block/17")
 3167     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-block/18")
 3168     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-in-block/19")
 3169     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-block/20")
 3170     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-block/21")
 3171     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-block/22")
 3172     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-block/23")
 3173     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-block/24")
 3174     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-block/25")
 3175     # . epilogue
 3176     89/<- %esp 5/r32/ebp
 3177     5d/pop-to-ebp
 3178     c3/return
 3179 
 3180 test-convert-function-with-branches-in-block-2:
 3181     # . prologue
 3182     55/push-ebp
 3183     89/<- %ebp 4/r32/esp
 3184     # setup
 3185     (clear-stream _test-input-stream)
 3186     (clear-stream $_test-input-buffered-file->buffer)
 3187     (clear-stream _test-output-stream)
 3188     (clear-stream $_test-output-buffered-file->buffer)
 3189     #
 3190     (write _test-input-stream "fn foo x: int {\n")
 3191     (write _test-input-stream "  {\n")
 3192     (write _test-input-stream "    break-if->=\n")
 3193     (write _test-input-stream "    loop-if-float<\n")
 3194     (write _test-input-stream "    increment x\n")
 3195     (write _test-input-stream "    loop\n")
 3196     (write _test-input-stream "  }\n")
 3197     (write _test-input-stream "}\n")
 3198     # convert
 3199     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3200     (flush _test-output-buffered-file)
 3201 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3207     # check output
 3208     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-block/0")
 3209     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-block/1")
 3210     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-block/2")
 3211     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-block/3")
 3212     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-block/4")
 3213     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-block/5")
 3214     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-block/6")
 3215     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-in-block/7")
 3216     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/8")
 3217     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-block/9")
 3218     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-in-block/10")
 3219     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/11")
 3220     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/12")
 3221     (check-next-stream-line-equal _test-output-stream "        0f 83/jump-if-addr>= break/disp32"  "F - test-convert-function-with-branches-in-block/13")
 3222     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:loop/disp32"  "F - test-convert-function-with-branches-in-block/14")
 3223     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/15")
 3224     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-block/16")
 3225     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-in-block/17")
 3226     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-block/18")
 3227     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-in-block/19")
 3228     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-block/20")
 3229     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-block/21")
 3230     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-block/22")
 3231     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-block/23")
 3232     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-block/24")
 3233     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-block/25")
 3234     # . epilogue
 3235     89/<- %esp 5/r32/ebp
 3236     5d/pop-to-ebp
 3237     c3/return
 3238 
 3239 test-convert-function-with-branches-in-named-block:
 3240     # . prologue
 3241     55/push-ebp
 3242     89/<- %ebp 4/r32/esp
 3243     # setup
 3244     (clear-stream _test-input-stream)
 3245     (clear-stream $_test-input-buffered-file->buffer)
 3246     (clear-stream _test-output-stream)
 3247     (clear-stream $_test-output-buffered-file->buffer)
 3248     #
 3249     (write _test-input-stream "fn foo x: int {\n")
 3250     (write _test-input-stream "  $bar: {\n")
 3251     (write _test-input-stream "    break-if->= $bar\n")
 3252     (write _test-input-stream "    loop-if-addr< $bar\n")
 3253     (write _test-input-stream "    increment x\n")
 3254     (write _test-input-stream "    loop\n")
 3255     (write _test-input-stream "  }\n")
 3256     (write _test-input-stream "}\n")
 3257     # convert
 3258     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3259     (flush _test-output-buffered-file)
 3260 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3266     # check output
 3267     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-named-block/0")
 3268     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-named-block/1")
 3269     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-named-block/2")
 3270     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-named-block/3")
 3271     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-named-block/4")
 3272     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-named-block/5")
 3273     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-named-block/6")
 3274     (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-branches-in-named-block/7")
 3275     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-named-block/8")
 3276     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-named-block/9")
 3277     (check-next-stream-line-equal _test-output-stream "        e9/jump $bar:break/disp32"  "F - test-convert-function-with-branches-in-named-block/10")
 3278     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-named-block/11")
 3279     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-named-block/12")
 3280     (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")
 3281     (check-next-stream-line-equal _test-output-stream "        e9/jump $bar:loop/disp32"  "F - test-convert-function-with-branches-in-named-block/14")
 3282     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-named-block/15")
 3283     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-named-block/16")
 3284     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"   "F - test-convert-function-with-branches-in-named-block/17")
 3285     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-named-block/18")
 3286     (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-branches-in-named-block/19")
 3287     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-named-block/20")
 3288     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-named-block/21")
 3289     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-named-block/22")
 3290     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-named-block/23")
 3291     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-named-block/24")
 3292     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-named-block/25")
 3293     # . epilogue
 3294     89/<- %esp 5/r32/ebp
 3295     5d/pop-to-ebp
 3296     c3/return
 3297 
 3298 test-convert-function-with-var-in-nested-block:
 3299     # . prologue
 3300     55/push-ebp
 3301     89/<- %ebp 4/r32/esp
 3302     # setup
 3303     (clear-stream _test-input-stream)
 3304     (clear-stream $_test-input-buffered-file->buffer)
 3305     (clear-stream _test-output-stream)
 3306     (clear-stream $_test-output-buffered-file->buffer)
 3307     #
 3308     (write _test-input-stream "fn foo x: int {\n")
 3309     (write _test-input-stream "  {\n")
 3310     (write _test-input-stream "    {\n")
 3311     (write _test-input-stream "      var x: int\n")
 3312     (write _test-input-stream "      increment x\n")
 3313     (write _test-input-stream "    }\n")
 3314     (write _test-input-stream "  }\n")
 3315     (write _test-input-stream "}\n")
 3316     # convert
 3317     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3318     (flush _test-output-buffered-file)
 3319 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3325     # check output
 3326     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-var-in-nested-block/0")
 3327     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-var-in-nested-block/1")
 3328     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-var-in-nested-block/2")
 3329     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-var-in-nested-block/3")
 3330     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-var-in-nested-block/4")
 3331     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-var-in-nested-block/5")
 3332     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-var-in-nested-block/6")
 3333     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-var-in-nested-block/7")
 3334     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-var-in-nested-block/8")
 3335     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-var-in-nested-block/9")
 3336     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-var-in-nested-block/10")
 3337     (check-next-stream-line-equal _test-output-stream "        ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-var-in-nested-block/11")
 3338     (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")
 3339     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-var-in-nested-block/13")
 3340     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-var-in-nested-block/14")
 3341     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-var-in-nested-block/15")
 3342     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-var-in-nested-block/16")
 3343     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-var-in-nested-block/17")
 3344     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-var-in-nested-block/18")
 3345     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-var-in-nested-block/19")
 3346     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-var-in-nested-block/20")
 3347     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-var-in-nested-block/21")
 3348     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-var-in-nested-block/22")
 3349     # . epilogue
 3350     89/<- %esp 5/r32/ebp
 3351     5d/pop-to-ebp
 3352     c3/return
 3353 
 3354 test-convert-function-with-multiple-vars-in-nested-blocks:
 3355     # . prologue
 3356     55/push-ebp
 3357     89/<- %ebp 4/r32/esp
 3358     # setup
 3359     (clear-stream _test-input-stream)
 3360     (clear-stream $_test-input-buffered-file->buffer)
 3361     (clear-stream _test-output-stream)
 3362     (clear-stream $_test-output-buffered-file->buffer)
 3363     #
 3364     (write _test-input-stream "fn foo x: int {\n")
 3365     (write _test-input-stream "  {\n")
 3366     (write _test-input-stream "    var x/eax: int <- copy 0\n")
 3367     (write _test-input-stream "    {\n")
 3368     (write _test-input-stream "      var y: int\n")
 3369     (write _test-input-stream "      x <- add y\n")
 3370     (write _test-input-stream "    }\n")
 3371     (write _test-input-stream "  }\n")
 3372     (write _test-input-stream "}\n")
 3373     # convert
 3374     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3375     (flush _test-output-buffered-file)
 3376 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3382     # check output
 3383     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-multiple-vars-in-nested-blocks/0")
 3384     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/1")
 3385     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-multiple-vars-in-nested-blocks/2")
 3386     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/3")
 3387     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/4")
 3388     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/5")
 3389     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/6")
 3390     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/7")
 3391     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %eax"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/8")
 3392     (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")
 3393     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/10")
 3394     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/11")
 3395     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-multiple-vars-in-nested-blocks/12")
 3396     (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")
 3397     (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")
 3398     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/15")
 3399     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/16")
 3400     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %eax"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/17")
 3401     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/18")
 3402     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/19")
 3403     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/20")
 3404     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/21")
 3405     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/22")
 3406     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/23")
 3407     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-multiple-vars-in-nested-blocks/24")
 3408     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-multiple-vars-in-nested-blocks/25")
 3409     # . epilogue
 3410     89/<- %esp 5/r32/ebp
 3411     5d/pop-to-ebp
 3412     c3/return
 3413 
 3414 test-convert-function-with-branches-and-local-vars:
 3415     # A conditional 'break' after a 'var' in a block is converted into a
 3416     # nested block that performs all necessary cleanup before jumping. This
 3417     # results in some ugly code duplication.
 3418     # . prologue
 3419     55/push-ebp
 3420     89/<- %ebp 4/r32/esp
 3421     # setup
 3422     (clear-stream _test-input-stream)
 3423     (clear-stream $_test-input-buffered-file->buffer)
 3424     (clear-stream _test-output-stream)
 3425     (clear-stream $_test-output-buffered-file->buffer)
 3426     #
 3427     (write _test-input-stream "fn foo {\n")
 3428     (write _test-input-stream "  {\n")
 3429     (write _test-input-stream "    var x: int\n")
 3430     (write _test-input-stream "    break-if->=\n")
 3431     (write _test-input-stream "    increment x\n")
 3432     (write _test-input-stream "  }\n")
 3433     (write _test-input-stream "}\n")
 3434     # convert
 3435     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3436     (flush _test-output-buffered-file)
 3437 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3443     # check output
 3444     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-local-vars/0")
 3445     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-local-vars/1")
 3446     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-local-vars/2")
 3447     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-and-local-vars/3")
 3448     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-local-vars/4")
 3449     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-local-vars/5")
 3450     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-local-vars/6")
 3451     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-local-vars/7")
 3452     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-local-vars/8")
 3453     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-local-vars/9")
 3454     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-and-local-vars/10")
 3455     (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")
 3456     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-and-local-vars/12")
 3457     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-local-vars/13")
 3458     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-branches-and-local-vars/14")
 3459     (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")
 3460     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-local-vars/16")
 3461     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-local-vars/17")
 3462     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-local-vars/18")
 3463     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-local-vars/19")
 3464     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-local-vars/20")
 3465     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-and-local-vars/21")
 3466     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-local-vars/22")
 3467     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-local-vars/23")
 3468     # . epilogue
 3469     89/<- %esp 5/r32/ebp
 3470     5d/pop-to-ebp
 3471     c3/return
 3472 
 3473 test-convert-function-with-conditional-loops-and-local-vars:
 3474     # A conditional 'loop' after a 'var' in a block is converted into a nested
 3475     # block that performs all necessary cleanup before jumping. This results
 3476     # in some ugly code duplication.
 3477     # . prologue
 3478     55/push-ebp
 3479     89/<- %ebp 4/r32/esp
 3480     # setup
 3481     (clear-stream _test-input-stream)
 3482     (clear-stream $_test-input-buffered-file->buffer)
 3483     (clear-stream _test-output-stream)
 3484     (clear-stream $_test-output-buffered-file->buffer)
 3485     #
 3486     (write _test-input-stream "fn foo {\n")
 3487     (write _test-input-stream "  {\n")
 3488     (write _test-input-stream "    var x: int\n")
 3489     (write _test-input-stream "    loop-if->=\n")
 3490     (write _test-input-stream "    increment x\n")
 3491     (write _test-input-stream "  }\n")
 3492     (write _test-input-stream "}\n")
 3493     # convert
 3494     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3495     (flush _test-output-buffered-file)
 3496 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3502     # check output
 3503     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-conditional-loops-and-local-vars/0")
 3504     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-conditional-loops-and-local-vars/1")
 3505     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-conditional-loops-and-local-vars/2")
 3506     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-conditional-loops-and-local-vars/3")
 3507     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-conditional-loops-and-local-vars/4")
 3508     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/5")
 3509     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-conditional-loops-and-local-vars/6")
 3510     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/7")
 3511     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-conditional-loops-and-local-vars/8")
 3512     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-conditional-loops-and-local-vars/9")
 3513     (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")
 3514     (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")
 3515     (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")
 3516     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-conditional-loops-and-local-vars/13")
 3517     (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")
 3518     (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")
 3519     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-conditional-loops-and-local-vars/16")
 3520     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/17")
 3521     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-conditional-loops-and-local-vars/18")
 3522     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/19")
 3523     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-conditional-loops-and-local-vars/20")
 3524     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-conditional-loops-and-local-vars/21")
 3525     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-conditional-loops-and-local-vars/22")
 3526     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-conditional-loops-and-local-vars/23")
 3527     # . epilogue
 3528     89/<- %esp 5/r32/ebp
 3529     5d/pop-to-ebp
 3530     c3/return
 3531 
 3532 test-convert-function-with-unconditional-loops-and-local-vars:
 3533     # An unconditional 'loop' after a 'var' in a block is emitted _after_ the
 3534     # regular block cleanup. Any instructions after 'loop' are dead and
 3535     # therefore skipped.
 3536     # . prologue
 3537     55/push-ebp
 3538     89/<- %ebp 4/r32/esp
 3539     # setup
 3540     (clear-stream _test-input-stream)
 3541     (clear-stream $_test-input-buffered-file->buffer)
 3542     (clear-stream _test-output-stream)
 3543     (clear-stream $_test-output-buffered-file->buffer)
 3544     #
 3545     (write _test-input-stream "fn foo {\n")
 3546     (write _test-input-stream "  {\n")
 3547     (write _test-input-stream "    var x: int\n")
 3548     (write _test-input-stream "    loop\n")
 3549     (write _test-input-stream "    increment x\n")
 3550     (write _test-input-stream "  }\n")
 3551     (write _test-input-stream "}\n")
 3552     # convert
 3553     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3554     (flush _test-output-buffered-file)
 3555 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3561     # check output
 3562     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-loops-and-local-vars/0")
 3563     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/1")
 3564     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-loops-and-local-vars/2")
 3565     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/3")
 3566     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/4")
 3567     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/5")
 3568     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/6")
 3569     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/7")
 3570     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-loops-and-local-vars/8")
 3571     (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")
 3572     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-unconditional-loops-and-local-vars/10")
 3573     # not emitted:                                           ff 0/subop/increment *(ebp+0xfffffffc)
 3574     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/11")
 3575     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/12")
 3576     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/13")
 3577     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/14")
 3578     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/15")
 3579     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/16")
 3580     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-loops-and-local-vars/17")
 3581     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-loops-and-local-vars/18")
 3582     # . epilogue
 3583     89/<- %esp 5/r32/ebp
 3584     5d/pop-to-ebp
 3585     c3/return
 3586 
 3587 test-convert-function-with-branches-and-loops-and-local-vars:
 3588     # . prologue
 3589     55/push-ebp
 3590     89/<- %ebp 4/r32/esp
 3591     # setup
 3592     (clear-stream _test-input-stream)
 3593     (clear-stream $_test-input-buffered-file->buffer)
 3594     (clear-stream _test-output-stream)
 3595     (clear-stream $_test-output-buffered-file->buffer)
 3596     #
 3597     (write _test-input-stream "fn foo {\n")
 3598     (write _test-input-stream "  {\n")
 3599     (write _test-input-stream "    var x: int\n")
 3600     (write _test-input-stream "    break-if->=\n")
 3601     (write _test-input-stream "    increment x\n")
 3602     (write _test-input-stream "    loop\n")
 3603     (write _test-input-stream "  }\n")
 3604     (write _test-input-stream "}\n")
 3605     # convert
 3606     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3607     (flush _test-output-buffered-file)
 3608 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3614     # check output
 3615     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-loops-and-local-vars/0")
 3616     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/1")
 3617     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-loops-and-local-vars/2")
 3618     (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")
 3619     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/4")
 3620     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/5")
 3621     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/6")
 3622     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/7")
 3623     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-loops-and-local-vars/8")
 3624     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/9")
 3625     (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")
 3626     (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")
 3627     (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")
 3628     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/13")
 3629     (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")
 3630     (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")
 3631     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-and-loops-and-local-vars/16")
 3632     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/17")
 3633     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/18")
 3634     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/19")
 3635     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/20")
 3636     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/21")
 3637     (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")
 3638     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-loops-and-local-vars/23")
 3639     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-loops-and-local-vars/24")
 3640     # . epilogue
 3641     89/<- %esp 5/r32/ebp
 3642     5d/pop-to-ebp
 3643     c3/return
 3644 
 3645 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars:
 3646     # . prologue
 3647     55/push-ebp
 3648     89/<- %ebp 4/r32/esp
 3649     # setup
 3650     (clear-stream _test-input-stream)
 3651     (clear-stream $_test-input-buffered-file->buffer)
 3652     (clear-stream _test-output-stream)
 3653     (clear-stream $_test-output-buffered-file->buffer)
 3654     #
 3655     (write _test-input-stream "fn foo {\n")
 3656     (write _test-input-stream "  a: {\n")
 3657     (write _test-input-stream "    var x: int\n")
 3658     (write _test-input-stream "    {\n")
 3659     (write _test-input-stream "      var y: int\n")
 3660     (write _test-input-stream "      break-if->= a\n")
 3661     (write _test-input-stream "      increment x\n")
 3662     (write _test-input-stream "      loop\n")
 3663     (write _test-input-stream "    }\n")
 3664     (write _test-input-stream "  }\n")
 3665     (write _test-input-stream "}\n")
 3666     # convert
 3667     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3668     (flush _test-output-buffered-file)
 3669 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3675     # check output
 3676     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/0")
 3677     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/1")
 3678     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/2")
 3679     (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")
 3680     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/4")
 3681     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/5")
 3682     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/6")
 3683     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/7")
 3684     (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")
 3685     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/9")
 3686     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/10")
 3687     (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")
 3688     (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/12")
 3689     (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")
 3690     (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")
 3691     (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")
 3692     (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")
 3693     (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/17")
 3694     (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")
 3695     (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")
 3696     (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")
 3697     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/21")
 3698     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/22")
 3699     (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")
 3700     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/24")
 3701     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/25")
 3702     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/26")
 3703     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/27")
 3704     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/28")
 3705     (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")
 3706     (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")
 3707     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/31")
 3708     # . epilogue
 3709     89/<- %esp 5/r32/ebp
 3710     5d/pop-to-ebp
 3711     c3/return
 3712 
 3713 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2:
 3714     # . prologue
 3715     55/push-ebp
 3716     89/<- %ebp 4/r32/esp
 3717     # setup
 3718     (clear-stream _test-input-stream)
 3719     (clear-stream $_test-input-buffered-file->buffer)
 3720     (clear-stream _test-output-stream)
 3721     (clear-stream $_test-output-buffered-file->buffer)
 3722     # non-local conditional branch from a block without a local variable,
 3723     # unwinding a local on the stack
 3724     (write _test-input-stream "fn foo {\n")
 3725     (write _test-input-stream "  a: {\n")
 3726     (write _test-input-stream "    var x: int\n")
 3727     (write _test-input-stream "    {\n")
 3728     (write _test-input-stream "      break-if->= a\n")
 3729     (write _test-input-stream "    }\n")
 3730     (write _test-input-stream "  }\n")
 3731     (write _test-input-stream "}\n")
 3732     # convert
 3733     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3734     (flush _test-output-buffered-file)
 3735 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3741     # check output
 3742     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/0")
 3743     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/1")
 3744     (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")
 3745     (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")
 3746     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/4")
 3747     (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")
 3748     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/6")
 3749     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/7")
 3750     (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")
 3751     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/9")
 3752     (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")
 3753     (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/11")
 3754     (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")
 3755     (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")
 3756     (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")
 3757     (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/15")
 3758     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/16")
 3759     (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")
 3760     (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")
 3761     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/19")
 3762     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/20")
 3763     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/21")
 3764     (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")
 3765     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/23")
 3766     (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")
 3767     (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")
 3768     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/26")
 3769     # . epilogue
 3770     89/<- %esp 5/r32/ebp
 3771     5d/pop-to-ebp
 3772     c3/return
 3773 
 3774 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3:
 3775     # . prologue
 3776     55/push-ebp
 3777     89/<- %ebp 4/r32/esp
 3778     # setup
 3779     (clear-stream _test-input-stream)
 3780     (clear-stream $_test-input-buffered-file->buffer)
 3781     (clear-stream _test-output-stream)
 3782     (clear-stream $_test-output-buffered-file->buffer)
 3783     # non-local unconditional branch from a block without a local variable,
 3784     # unwinding a local on the stack
 3785     (write _test-input-stream "fn foo {\n")
 3786     (write _test-input-stream "  a: {\n")
 3787     (write _test-input-stream "    var x: int\n")
 3788     (write _test-input-stream "    {\n")
 3789     (write _test-input-stream "      break a\n")
 3790     (write _test-input-stream "    }\n")
 3791     (write _test-input-stream "  }\n")
 3792     (write _test-input-stream "}\n")
 3793     # convert
 3794     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3795     (flush _test-output-buffered-file)
 3796 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3802     # check output
 3803     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/0")
 3804     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/1")
 3805     (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")
 3806     (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")
 3807     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/4")
 3808     (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")
 3809     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/6")
 3810     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/7")
 3811     (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")
 3812     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/9")
 3813     (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")
 3814     (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")
 3815     (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")
 3816     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/14")
 3817     (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")
 3818     (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")
 3819     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/17")
 3820     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/18")
 3821     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/19")
 3822     (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")
 3823     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/21")
 3824     (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")
 3825     (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")
 3826     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/24")
 3827     # . epilogue
 3828     89/<- %esp 5/r32/ebp
 3829     5d/pop-to-ebp
 3830     c3/return
 3831 
 3832 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4:
 3833     # . prologue
 3834     55/push-ebp
 3835     89/<- %ebp 4/r32/esp
 3836     # setup
 3837     (clear-stream _test-input-stream)
 3838     (clear-stream $_test-input-buffered-file->buffer)
 3839     (clear-stream _test-output-stream)
 3840     (clear-stream $_test-output-buffered-file->buffer)
 3841     #
 3842     (write _test-input-stream "fn foo {\n")
 3843     (write _test-input-stream "  a: {\n")
 3844     (write _test-input-stream "    var x/esi: int <- copy 0\n")
 3845     (write _test-input-stream "    {\n")
 3846     (write _test-input-stream "      break a\n")
 3847     (write _test-input-stream "    }\n")
 3848     (write _test-input-stream "  }\n")
 3849     (write _test-input-stream "}\n")
 3850     # convert
 3851     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3852     (flush _test-output-buffered-file)
 3853 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3859     # check output
 3860     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/0")
 3861     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/1")
 3862     (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")
 3863     (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")
 3864     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/4")
 3865     (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")
 3866     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/6")
 3867     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/7")
 3868     (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")
 3869     (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")
 3870     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/10")
 3871     (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")
 3872     (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")
 3873     (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")
 3874     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/14")
 3875     (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")
 3876     (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")
 3877     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/17")
 3878     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/18")
 3879     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/19")
 3880     (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")
 3881     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/21")
 3882     (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")
 3883     (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")
 3884     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/24")
 3885     # . epilogue
 3886     89/<- %esp 5/r32/ebp
 3887     5d/pop-to-ebp
 3888     c3/return
 3889 
 3890 test-convert-function-with-nonlocal-unconditional-break-and-local-vars:
 3891     # . prologue
 3892     55/push-ebp
 3893     89/<- %ebp 4/r32/esp
 3894     # setup
 3895     (clear-stream _test-input-stream)
 3896     (clear-stream $_test-input-buffered-file->buffer)
 3897     (clear-stream _test-output-stream)
 3898     (clear-stream $_test-output-buffered-file->buffer)
 3899     #
 3900     (write _test-input-stream "fn foo {\n")
 3901     (write _test-input-stream "  a: {\n")
 3902     (write _test-input-stream "    var x: int\n")
 3903     (write _test-input-stream "    {\n")
 3904     (write _test-input-stream "      var y: int\n")
 3905     (write _test-input-stream "      break a\n")
 3906     (write _test-input-stream "      increment x\n")
 3907     (write _test-input-stream "    }\n")
 3908     (write _test-input-stream "  }\n")
 3909     (write _test-input-stream "}\n")
 3910     # convert
 3911     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3912     (flush _test-output-buffered-file)
 3913 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3919     # check output
 3920     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/0")
 3921     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/1")
 3922     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/2")
 3923     (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")
 3924     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/4")
 3925     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/5")
 3926     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/6")
 3927     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/7")
 3928     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/8")
 3929     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/9")
 3930     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/10")
 3931     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/11")
 3932     (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")
 3933     (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")
 3934     (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")
 3935     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/15")
 3936     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/16")
 3937     (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")
 3938     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/18")
 3939     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/19")
 3940     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/20")
 3941     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/21")
 3942     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/22")
 3943     (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")
 3944     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/24")
 3945     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/25")
 3946     # . epilogue
 3947     89/<- %esp 5/r32/ebp
 3948     5d/pop-to-ebp
 3949     c3/return
 3950 
 3951 test-convert-function-with-unconditional-break-and-local-vars:
 3952     # . prologue
 3953     55/push-ebp
 3954     89/<- %ebp 4/r32/esp
 3955     # setup
 3956     (clear-stream _test-input-stream)
 3957     (clear-stream $_test-input-buffered-file->buffer)
 3958     (clear-stream _test-output-stream)
 3959     (clear-stream $_test-output-buffered-file->buffer)
 3960     #
 3961     (write _test-input-stream "fn foo {\n")
 3962     (write _test-input-stream "  {\n")
 3963     (write _test-input-stream "    var x: int\n")
 3964     (write _test-input-stream "    {\n")
 3965     (write _test-input-stream "      var y: int\n")
 3966     (write _test-input-stream "      break\n")
 3967     (write _test-input-stream "      increment x\n")
 3968     (write _test-input-stream "    }\n")
 3969     (write _test-input-stream "  }\n")
 3970     (write _test-input-stream "}\n")
 3971     # convert
 3972     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3973     (flush _test-output-buffered-file)
 3974 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3980     # check output
 3981     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-break-and-local-vars/0")
 3982     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-break-and-local-vars/1")
 3983     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-break-and-local-vars/2")
 3984     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-break-and-local-vars/3")
 3985     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-break-and-local-vars/4")
 3986     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/5")
 3987     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-break-and-local-vars/6")
 3988     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/7")
 3989     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-break-and-local-vars/8")
 3990     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-unconditional-break-and-local-vars/9")
 3991     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/10")
 3992     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/11")
 3993     (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")
 3994     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-unconditional-break-and-local-vars/13")
 3995     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/14")
 3996     (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")
 3997     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-break-and-local-vars/16")
 3998     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/17")
 3999     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-break-and-local-vars/18")
 4000     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/19")
 4001     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-break-and-local-vars/20")
 4002     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-break-and-local-vars/21")
 4003     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-break-and-local-vars/22")
 4004     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-break-and-local-vars/23")
 4005     # . epilogue
 4006     89/<- %esp 5/r32/ebp
 4007     5d/pop-to-ebp
 4008     c3/return
 4009 
 4010 test-convert-function-with-nonlocal-unconditional-loop-and-local-vars:
 4011     # . prologue
 4012     55/push-ebp
 4013     89/<- %ebp 4/r32/esp
 4014     # setup
 4015     (clear-stream _test-input-stream)
 4016     (clear-stream $_test-input-buffered-file->buffer)
 4017     (clear-stream _test-output-stream)
 4018     (clear-stream $_test-output-buffered-file->buffer)
 4019     #
 4020     (write _test-input-stream "fn foo {\n")
 4021     (write _test-input-stream "  a: {\n")
 4022     (write _test-input-stream "    var x: int\n")
 4023     (write _test-input-stream "    {\n")
 4024     (write _test-input-stream "      var y: int\n")
 4025     (write _test-input-stream "      loop a\n")
 4026     (write _test-input-stream "      increment x\n")
 4027     (write _test-input-stream "    }\n")
 4028     (write _test-input-stream "  }\n")
 4029     (write _test-input-stream "}\n")
 4030     # convert
 4031     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4032     (flush _test-output-buffered-file)
 4033 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4039     # check output
 4040     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/0")
 4041     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/1")
 4042     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/2")
 4043     (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")
 4044     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/4")
 4045     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/5")
 4046     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/6")
 4047     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/7")
 4048     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/8")
 4049     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/9")
 4050     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/10")
 4051     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/11")
 4052     (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")
 4053     (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")
 4054     (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")
 4055     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/15")
 4056     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/16")
 4057     (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")
 4058     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/18")
 4059     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/19")
 4060     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/20")
 4061     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/21")
 4062     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/22")
 4063     (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")
 4064     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/24")
 4065     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/25")
 4066     # . epilogue
 4067     89/<- %esp 5/r32/ebp
 4068     5d/pop-to-ebp
 4069     c3/return
 4070 
 4071 test-convert-function-with-local-array-var-in-mem:
 4072     # . prologue
 4073     55/push-ebp
 4074     89/<- %ebp 4/r32/esp
 4075     # setup
 4076     (clear-stream _test-input-stream)
 4077     (clear-stream $_test-input-buffered-file->buffer)
 4078     (clear-stream _test-output-stream)
 4079     (clear-stream $_test-output-buffered-file->buffer)
 4080     #
 4081     (write _test-input-stream "fn foo {\n")
 4082     (write _test-input-stream "  var x: (array int 3)\n")
 4083     (write _test-input-stream "}\n")
 4084     # convert
 4085     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4086     (flush _test-output-buffered-file)
 4087 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4093     # check output
 4094     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-array-var-in-mem/0")
 4095     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-array-var-in-mem/1")
 4096     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-array-var-in-mem/2")
 4097     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-array-var-in-mem/3")
 4098     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-array-var-in-mem/4")
 4099     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-array-var-in-mem/5")
 4100     # define x
 4101     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-function-with-local-array-var-in-mem/7")
 4102     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-function-with-local-array-var-in-mem/8")
 4103     # reclaim x
 4104     (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")
 4105     #
 4106     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-array-var-in-mem/10")
 4107     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-array-var-in-mem/11")
 4108     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-array-var-in-mem/12")
 4109     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-array-var-in-mem/13")
 4110     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-array-var-in-mem/14")
 4111     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-array-var-in-mem/15")
 4112     # . epilogue
 4113     89/<- %esp 5/r32/ebp
 4114     5d/pop-to-ebp
 4115     c3/return
 4116 
 4117 test-array-size-in-hex:
 4118     # . prologue
 4119     55/push-ebp
 4120     89/<- %ebp 4/r32/esp
 4121     # setup
 4122     (clear-stream _test-input-stream)
 4123     (clear-stream $_test-input-buffered-file->buffer)
 4124     (clear-stream _test-output-stream)
 4125     (clear-stream $_test-output-buffered-file->buffer)
 4126     (clear-stream _test-error-stream)
 4127     (clear-stream $_test-error-buffered-file->buffer)
 4128     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 4129     68/push 0/imm32
 4130     68/push 0/imm32
 4131     89/<- %edx 4/r32/esp
 4132     (tailor-exit-descriptor %edx 0x10)
 4133     #
 4134     (write _test-input-stream "fn foo {\n")
 4135     (write _test-input-stream "  var x: (array int 10)\n")
 4136     (write _test-input-stream "}\n")
 4137     # convert
 4138     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 4139     # registers except esp clobbered at this point
 4140     # restore ed
 4141     89/<- %edx 4/r32/esp
 4142     (flush _test-output-buffered-file)
 4143     (flush _test-error-buffered-file)
 4144 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4150     # check output
 4151     (check-stream-equal _test-output-stream  ""  "F - test-array-size-in-hex: output should be empty")
 4152     (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")
 4153     # check that stop(1) was called
 4154     (check-ints-equal *(edx+4) 2 "F - test-array-size-in-hex: exit status")
 4155     # don't restore from ebp
 4156     81 0/subop/add %esp 8/imm32
 4157     # . epilogue
 4158     5d/pop-to-ebp
 4159     c3/return
 4160 
 4161 test-convert-function-with-populate:
 4162     # . prologue
 4163     55/push-ebp
 4164     89/<- %ebp 4/r32/esp
 4165     # setup
 4166     (clear-stream _test-input-stream)
 4167     (clear-stream $_test-input-buffered-file->buffer)
 4168     (clear-stream _test-output-stream)
 4169     (clear-stream $_test-output-buffered-file->buffer)
 4170     #
 4171     (write _test-input-stream "fn foo {\n")
 4172     (write _test-input-stream "  var x/ecx: (addr handle array int) <- copy 0\n")
 4173     (write _test-input-stream "  populate x, 7\n")
 4174     (write _test-input-stream "}\n")
 4175     # convert
 4176     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4177     (flush _test-output-buffered-file)
 4178 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4184     # check output
 4185     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-populate/0")
 4186     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-populate/1")
 4187     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-populate/2")
 4188     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-populate/3")
 4189     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-populate/4")
 4190     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-populate/5")
 4191     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-populate/6")
 4192     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-populate/7")
 4193     (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)
 4194     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-populate/9")
 4195     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-populate/10")
 4196     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-populate/11")
 4197     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-populate/12")
 4198     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-populate/13")
 4199     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-populate/14")
 4200     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-populate/15")
 4201     # . epilogue
 4202     89/<- %esp 5/r32/ebp
 4203     5d/pop-to-ebp
 4204     c3/return
 4205 
 4206 # special-case for size(byte) when allocating array
 4207 test-convert-function-with-local-array-of-bytes-in-mem:
 4208     # . prologue
 4209     55/push-ebp
 4210     89/<- %ebp 4/r32/esp
 4211     # setup
 4212     (clear-stream _test-input-stream)
 4213     (clear-stream $_test-input-buffered-file->buffer)
 4214     (clear-stream _test-output-stream)
 4215     (clear-stream $_test-output-buffered-file->buffer)
 4216     #
 4217     (write _test-input-stream "fn foo {\n")
 4218     (write _test-input-stream "  var x: (array byte 3)\n")
 4219     (write _test-input-stream "}\n")
 4220     # convert
 4221     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4222     (flush _test-output-buffered-file)
 4223 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4229     # check output
 4230     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-array-of-bytes-in-mem/0")
 4231     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-array-of-bytes-in-mem/1")
 4232     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-array-of-bytes-in-mem/2")
 4233     (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")
 4234     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-array-of-bytes-in-mem/4")
 4235     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-array-of-bytes-in-mem/5")
 4236     # define x
 4237     (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")
 4238     (check-next-stream-line-equal _test-output-stream "    68/push 0x00000003/imm32"  "F - test-convert-function-with-local-array-of-bytes-in-mem/8")
 4239     # reclaim x
 4240     (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")
 4241     #
 4242     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-array-of-bytes-in-mem/10")
 4243     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-array-of-bytes-in-mem/11")
 4244     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-array-of-bytes-in-mem/12")
 4245     (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")
 4246     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-array-of-bytes-in-mem/14")
 4247     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-array-of-bytes-in-mem/15")
 4248     # . epilogue
 4249     89/<- %esp 5/r32/ebp
 4250     5d/pop-to-ebp
 4251     c3/return
 4252 
 4253 test-convert-address:
 4254     # . prologue
 4255     55/push-ebp
 4256     89/<- %ebp 4/r32/esp
 4257     # setup
 4258     (clear-stream _test-input-stream)
 4259     (clear-stream $_test-input-buffered-file->buffer)
 4260     (clear-stream _test-output-stream)
 4261     (clear-stream $_test-output-buffered-file->buffer)
 4262     #
 4263     (write _test-input-stream "fn foo {\n")
 4264     (write _test-input-stream "  var a: int\n")
 4265     (write _test-input-stream "  var b/eax: (addr int) <- address a\n")
 4266     (write _test-input-stream "}\n")
 4267     # convert
 4268     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4269     (flush _test-output-buffered-file)
 4270 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4276     # check output
 4277     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-address/0")
 4278     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-address/1")
 4279     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-address/2")
 4280     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-address/3")
 4281     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-address/4")
 4282     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-address/5")
 4283     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-address/6")
 4284     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-address/7")
 4285     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000000/r32"  "F - test-convert-address/8")
 4286     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-address/9")
 4287     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-address/10")
 4288     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-address/11")
 4289     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-address/12")
 4290     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-address/13")
 4291     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-address/14")
 4292     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-address/15")
 4293     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-address/16")
 4294     # . epilogue
 4295     89/<- %esp 5/r32/ebp
 4296     5d/pop-to-ebp
 4297     c3/return
 4298 
 4299 test-convert-floating-point-convert:
 4300     # . prologue
 4301     55/push-ebp
 4302     89/<- %ebp 4/r32/esp
 4303     # setup
 4304     (clear-stream _test-input-stream)
 4305     (clear-stream $_test-input-buffered-file->buffer)
 4306     (clear-stream _test-output-stream)
 4307     (clear-stream $_test-output-buffered-file->buffer)
 4308     #
 4309     (write _test-input-stream "fn foo {\n")
 4310     (write _test-input-stream "  var a/eax: int <- copy 0\n")
 4311     (write _test-input-stream "  var b/xmm1: float <- convert a\n")
 4312     (write _test-input-stream "}\n")
 4313     # convert
 4314     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4315     (flush _test-output-buffered-file)
 4316 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4322     # check output
 4323     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-floating-point-convert/0")
 4324     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-floating-point-convert/1")
 4325     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-floating-point-convert/2")
 4326     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-floating-point-convert/3")
 4327     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-floating-point-convert/4")
 4328     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-floating-point-convert/5")
 4329     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-floating-point-convert/6")
 4330     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"  "F - test-convert-floating-point-convert/7")
 4331     (check-next-stream-line-equal _test-output-stream "    81 5/subop/subtract %esp 4/imm32"  "F - test-convert-floating-point-convert/8")
 4332     (check-next-stream-line-equal _test-output-stream "    f3 0f 11/<- *esp 1/x32"  "F - test-convert-floating-point-convert/9")
 4333     (check-next-stream-line-equal _test-output-stream "    f3 0f 2a/convert-to-float %eax 0x00000001/x32"  "F - test-convert-floating-point-convert/10")
 4334     (check-next-stream-line-equal _test-output-stream "    f3 0f 10/-> *esp 1/x32"  "F - test-convert-floating-point-convert/11")
 4335     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 4/imm32"  "F - test-convert-length-of-array-on-stack/12")
 4336     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-convert-floating-point-convert/13")
 4337     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-floating-point-convert/14")
 4338     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-floating-point-convert/15")
 4339     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-floating-point-convert/16")
 4340     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-floating-point-convert/17")
 4341     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-floating-point-convert/18")
 4342     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-floating-point-convert/19")
 4343     # . epilogue
 4344     89/<- %esp 5/r32/ebp
 4345     5d/pop-to-ebp
 4346     c3/return
 4347 
 4348 test-convert-floating-point-convert-2:
 4349     # . prologue
 4350     55/push-ebp
 4351     89/<- %ebp 4/r32/esp
 4352     # setup
 4353     (clear-stream _test-input-stream)
 4354     (clear-stream $_test-input-buffered-file->buffer)
 4355     (clear-stream _test-output-stream)
 4356     (clear-stream $_test-output-buffered-file->buffer)
 4357     #
 4358     (write _test-input-stream "fn foo {\n")
 4359     (write _test-input-stream "  var a/eax: int <- copy 0\n")
 4360     (write _test-input-stream "  var b/xmm1: float <- convert a\n")
 4361     (write _test-input-stream "  a <- convert b\n")
 4362     (write _test-input-stream "}\n")
 4363     # convert
 4364     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4365     (flush _test-output-buffered-file)
 4366 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4372     # check output
 4373     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-floating-point-convert-2/0")
 4374     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-floating-point-convert-2/1")
 4375     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-floating-point-convert-2/2")
 4376     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-floating-point-convert-2/3")
 4377     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-floating-point-convert-2/4")
 4378     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-floating-point-convert-2/5")
 4379     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-floating-point-convert-2/6")
 4380     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"  "F - test-convert-floating-point-convert-2/7")
 4381     (check-next-stream-line-equal _test-output-stream "    81 5/subop/subtract %esp 4/imm32"  "F - test-convert-floating-point-convert-2/8")
 4382     (check-next-stream-line-equal _test-output-stream "    f3 0f 11/<- *esp 1/x32"  "F - test-convert-floating-point-convert-2/9")
 4383     (check-next-stream-line-equal _test-output-stream "    f3 0f 2a/convert-to-float %eax 0x00000001/x32"  "F - test-convert-floating-point-convert-2/10")
 4384     (check-next-stream-line-equal _test-output-stream "    f3 0f 2d/convert-to-int 3/mod 0x00000001/xm32 0x00000000/r32"  "F - test-convert-floating-point-convert-2/11")
 4385     (check-next-stream-line-equal _test-output-stream "    f3 0f 10/-> *esp 1/x32"  "F - test-convert-floating-point-convert-2/12")
 4386     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 4/imm32"  "F - test-convert-length-of-array-on-stack/13")
 4387     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-convert-floating-point-convert-2/14")
 4388     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-floating-point-convert-2/15")
 4389     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-floating-point-convert-2/16")
 4390     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-floating-point-convert-2/17")
 4391     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-floating-point-convert-2/18")
 4392     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-floating-point-convert-2/19")
 4393     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-floating-point-convert-2/20")
 4394     # . epilogue
 4395     89/<- %esp 5/r32/ebp
 4396     5d/pop-to-ebp
 4397     c3/return
 4398 
 4399 test-convert-floating-point-operation:
 4400     # . prologue
 4401     55/push-ebp
 4402     89/<- %ebp 4/r32/esp
 4403     # setup
 4404     (clear-stream _test-input-stream)
 4405     (clear-stream $_test-input-buffered-file->buffer)
 4406     (clear-stream _test-output-stream)
 4407     (clear-stream $_test-output-buffered-file->buffer)
 4408     #
 4409     (write _test-input-stream "fn f {\n")
 4410     (write _test-input-stream "  var m: float\n")
 4411     (write _test-input-stream "  var x/xmm1: float <- copy m\n")
 4412     (write _test-input-stream "  var y/xmm5: float <- copy m\n")
 4413     (write _test-input-stream "  x <- copy y\n")
 4414     (write _test-input-stream "  copy-to m, y\n")
 4415     (write _test-input-stream "  x <- add y\n")
 4416     (write _test-input-stream "  x <- add m\n")
 4417     (write _test-input-stream "  x <- subtract y\n")
 4418     (write _test-input-stream "  x <- subtract m\n")
 4419     (write _test-input-stream "  x <- multiply y\n")
 4420     (write _test-input-stream "  x <- multiply m\n")
 4421     (write _test-input-stream "  x <- divide y\n")
 4422     (write _test-input-stream "  x <- divide m\n")
 4423     (write _test-input-stream "  x <- reciprocal y\n")
 4424     (write _test-input-stream "  x <- reciprocal m\n")
 4425     (write _test-input-stream "  x <- square-root y\n")
 4426     (write _test-input-stream "  x <- square-root m\n")
 4427     (write _test-input-stream "  x <- inverse-square-root y\n")
 4428     (write _test-input-stream "  x <- inverse-square-root m\n")
 4429     (write _test-input-stream "  x <- max y\n")
 4430     (write _test-input-stream "  x <- max m\n")
 4431     (write _test-input-stream "  x <- min y\n")
 4432     (write _test-input-stream "  x <- min m\n")
 4433     (write _test-input-stream "  compare x, y\n")
 4434     (write _test-input-stream "  compare x, m\n")
 4435     (write _test-input-stream "}\n")
 4436     # convert
 4437     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4438     (flush _test-output-buffered-file)
 4439 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4445     # check output
 4446     (check-next-stream-line-equal _test-output-stream "f:"                                                                     "F - test-convert-floating-point-operation/0")
 4447     (check-next-stream-line-equal _test-output-stream "  # . prologue"                                                         "F - test-convert-floating-point-operation/1")
 4448     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                                                          "F - test-convert-floating-point-operation/2")
 4449     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                                                 "F - test-convert-floating-point-operation/3")
 4450     (check-next-stream-line-equal _test-output-stream "  {"                                                                    "F - test-convert-floating-point-operation/4")
 4451     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"                                                    "F - test-convert-floating-point-operation/5")
 4452     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"                                                    "F - test-convert-floating-point-operation/6")
 4453     (check-next-stream-line-equal _test-output-stream "    81 5/subop/subtract %esp 4/imm32"                                   "F - test-convert-floating-point-operation/7")
 4454     (check-next-stream-line-equal _test-output-stream "    f3 0f 11/<- *esp 1/x32"                                             "F - test-convert-floating-point-operation/8")
 4455     (check-next-stream-line-equal _test-output-stream "    f3 0f 10/copy *(ebp+0xfffffffc) 0x00000001/x32"                     "F - test-convert-floating-point-operation/9")
 4456     (check-next-stream-line-equal _test-output-stream "    81 5/subop/subtract %esp 4/imm32"                                   "F - test-convert-floating-point-operation/10")
 4457     (check-next-stream-line-equal _test-output-stream "    f3 0f 11/<- *esp 5/x32"                                             "F - test-convert-floating-point-operation/11")
 4458     (check-next-stream-line-equal _test-output-stream "    f3 0f 10/copy *(ebp+0xfffffffc) 0x00000005/x32"                     "F - test-convert-floating-point-operation/12")
 4459     (check-next-stream-line-equal _test-output-stream "    f3 0f 11/copy 3/mod 0x00000001/xm32 0x00000005/x32"                 "F - test-convert-floating-point-operation/13")
 4460     (check-next-stream-line-equal _test-output-stream "    f3 0f 11/copy *(ebp+0xfffffffc) 0x00000005/x32"                     "F - test-convert-floating-point-operation/14")
 4461     (check-next-stream-line-equal _test-output-stream "    f3 0f 58/add 3/mod 0x00000005/xm32 0x00000001/x32"                  "F - test-convert-floating-point-operation/15")
 4462     (check-next-stream-line-equal _test-output-stream "    f3 0f 58/add *(ebp+0xfffffffc) 0x00000001/x32"                      "F - test-convert-floating-point-operation/16")
 4463     (check-next-stream-line-equal _test-output-stream "    f3 0f 5c/subtract 3/mod 0x00000005/xm32 0x00000001/x32"             "F - test-convert-floating-point-operation/17")
 4464     (check-next-stream-line-equal _test-output-stream "    f3 0f 5c/subtract *(ebp+0xfffffffc) 0x00000001/x32"                 "F - test-convert-floating-point-operation/18")
 4465     (check-next-stream-line-equal _test-output-stream "    f3 0f 59/multiply 3/mod 0x00000005/xm32 0x00000001/x32"             "F - test-convert-floating-point-operation/19")
 4466     (check-next-stream-line-equal _test-output-stream "    f3 0f 59/multiply *(ebp+0xfffffffc) 0x00000001/x32"                 "F - test-convert-floating-point-operation/20")
 4467     (check-next-stream-line-equal _test-output-stream "    f3 0f 5e/divide 3/mod 0x00000005/xm32 0x00000001/x32"               "F - test-convert-floating-point-operation/21")
 4468     (check-next-stream-line-equal _test-output-stream "    f3 0f 5e/divide *(ebp+0xfffffffc) 0x00000001/x32"                   "F - test-convert-floating-point-operation/22")
 4469     (check-next-stream-line-equal _test-output-stream "    f3 0f 53/reciprocal 3/mod 0x00000005/xm32 0x00000001/x32"           "F - test-convert-floating-point-operation/23")
 4470     (check-next-stream-line-equal _test-output-stream "    f3 0f 53/reciprocal *(ebp+0xfffffffc) 0x00000001/x32"               "F - test-convert-floating-point-operation/24")
 4471     (check-next-stream-line-equal _test-output-stream "    f3 0f 51/square-root 3/mod 0x00000005/xm32 0x00000001/x32"          "F - test-convert-floating-point-operation/25")
 4472     (check-next-stream-line-equal _test-output-stream "    f3 0f 51/square-root *(ebp+0xfffffffc) 0x00000001/x32"              "F - test-convert-floating-point-operation/26")
 4473     (check-next-stream-line-equal _test-output-stream "    f3 0f 52/inverse-square-root 3/mod 0x00000005/xm32 0x00000001/x32"  "F - test-convert-floating-point-operation/27")
 4474     (check-next-stream-line-equal _test-output-stream "    f3 0f 52/inverse-square-root *(ebp+0xfffffffc) 0x00000001/x32"      "F - test-convert-floating-point-operation/28")
 4475     (check-next-stream-line-equal _test-output-stream "    f3 0f 5f/max 3/mod 0x00000005/xm32 0x00000001/x32"                  "F - test-convert-floating-point-operation/29")
 4476     (check-next-stream-line-equal _test-output-stream "    f3 0f 5f/max *(ebp+0xfffffffc) 0x00000001/x32"                      "F - test-convert-floating-point-operation/30")
 4477     (check-next-stream-line-equal _test-output-stream "    f3 0f 5d/min 3/mod 0x00000005/xm32 0x00000001/x32"                  "F - test-convert-floating-point-operation/31")
 4478     (check-next-stream-line-equal _test-output-stream "    f3 0f 5d/min *(ebp+0xfffffffc) 0x00000001/x32"                      "F - test-convert-floating-point-operation/32")
 4479     (check-next-stream-line-equal _test-output-stream "    0f 2f/compare 3/mod 0x00000001/xm32 0x00000005/x32"                 "F - test-convert-floating-point-operation/33")
 4480     (check-next-stream-line-equal _test-output-stream "    0f 2f/compare *(ebp+0xfffffffc) 0x00000001/x32"                     "F - test-convert-floating-point-operation/34")
 4481     (check-next-stream-line-equal _test-output-stream "    f3 0f 10/-> *esp 5/x32"                                             "F - test-convert-floating-point-operation/35")
 4482     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 4/imm32"                                        "F - test-convert-floating-point-operation/36")
 4483     (check-next-stream-line-equal _test-output-stream "    f3 0f 10/-> *esp 1/x32"                                             "F - test-convert-floating-point-operation/37")
 4484     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 4/imm32"                                        "F - test-convert-floating-point-operation/38")
 4485     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"                               "F - test-convert-floating-point-operation/39")
 4486     (check-next-stream-line-equal _test-output-stream "  }"                                                                    "F - test-convert-floating-point-operation/40")
 4487     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"                                                   "F - test-convert-floating-point-operation/41")
 4488     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                                                         "F - test-convert-floating-point-operation/42")
 4489     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                                                 "F - test-convert-floating-point-operation/43")
 4490     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                                                        "F - test-convert-floating-point-operation/44")
 4491     (check-next-stream-line-equal _test-output-stream "  c3/return"                                                            "F - test-convert-floating-point-operation/45")
 4492     # . epilogue
 4493     89/<- %esp 5/r32/ebp
 4494     5d/pop-to-ebp
 4495     c3/return
 4496 
 4497 test-convert-length-of-array:
 4498     # . prologue
 4499     55/push-ebp
 4500     89/<- %ebp 4/r32/esp
 4501     # setup
 4502     (clear-stream _test-input-stream)
 4503     (clear-stream $_test-input-buffered-file->buffer)
 4504     (clear-stream _test-output-stream)
 4505     (clear-stream $_test-output-buffered-file->buffer)
 4506     #
 4507     (write _test-input-stream "fn foo a: (addr array int) {\n")
 4508     (write _test-input-stream "  var b/eax: (addr array int) <- copy a\n")
 4509     (write _test-input-stream "  var c/eax: int <- length b\n")
 4510     (write _test-input-stream "}\n")
 4511     # convert
 4512     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4513     (flush _test-output-buffered-file)
 4514 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4520     # check output
 4521     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array/0")
 4522     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array/1")
 4523     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array/2")
 4524     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array/3")
 4525     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array/4")
 4526     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array/5")
 4527     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array/6")
 4528     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-length-of-array/7")
 4529     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array/8")
 4530     (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array/9")
 4531     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array/10")
 4532     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array/11")
 4533     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array/12")
 4534     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array/13")
 4535     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array/14")
 4536     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array/15")
 4537     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array/16")
 4538     # . epilogue
 4539     89/<- %esp 5/r32/ebp
 4540     5d/pop-to-ebp
 4541     c3/return
 4542 
 4543 # special-case for size(byte) when computing array length
 4544 test-convert-length-of-array-of-bytes:
 4545     # . prologue
 4546     55/push-ebp
 4547     89/<- %ebp 4/r32/esp
 4548     # setup
 4549     (clear-stream _test-input-stream)
 4550     (clear-stream $_test-input-buffered-file->buffer)
 4551     (clear-stream _test-output-stream)
 4552     (clear-stream $_test-output-buffered-file->buffer)
 4553     #
 4554     (write _test-input-stream "fn foo a: (addr array byte) {\n")
 4555     (write _test-input-stream "  var b/eax: (addr array byte) <- copy a\n")
 4556     (write _test-input-stream "  var c/eax: int <- length b\n")
 4557     (write _test-input-stream "}\n")
 4558     # convert
 4559     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4560     (flush _test-output-buffered-file)
 4561 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4567     # check output
 4568     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-bytes/0")
 4569     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-bytes/1")
 4570     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-bytes/2")
 4571     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-bytes/3")
 4572     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-bytes/4")
 4573     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-bytes/5")
 4574     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-bytes/6")
 4575     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-length-of-array-of-bytes/7")
 4576     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-bytes/8")
 4577     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-bytes/9")
 4578     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-bytes/10")
 4579     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-bytes/11")
 4580     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-bytes/12")
 4581     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-bytes/13")
 4582     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-bytes/14")
 4583     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-bytes/15")
 4584     # . epilogue
 4585     89/<- %esp 5/r32/ebp
 4586     5d/pop-to-ebp
 4587     c3/return
 4588 
 4589 test-convert-length-of-array-on-stack:
 4590     # . prologue
 4591     55/push-ebp
 4592     89/<- %ebp 4/r32/esp
 4593     # setup
 4594     (clear-stream _test-input-stream)
 4595     (clear-stream $_test-input-buffered-file->buffer)
 4596     (clear-stream _test-output-stream)
 4597     (clear-stream $_test-output-buffered-file->buffer)
 4598     #
 4599     (write _test-input-stream "fn foo {\n")
 4600     (write _test-input-stream "  var a: (array int 3)\n")
 4601     (write _test-input-stream "  var b/eax: int <- length a\n")
 4602     (write _test-input-stream "}\n")
 4603     # convert
 4604     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4605     (flush _test-output-buffered-file)
 4606 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4612     # check output
 4613     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-on-stack/0")
 4614     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-on-stack/1")
 4615     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-on-stack/2")
 4616     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-on-stack/3")
 4617     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-on-stack/4")
 4618     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-on-stack/5")
 4619     # define x
 4620     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-length-of-array-on-stack/6")
 4621     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-length-of-array-on-stack/7")
 4622     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-on-stack/8")
 4623     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0xfffffff0) 0x00000000/r32"  "F - test-convert-length-of-array-on-stack/9")
 4624     (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array-on-stack/10")
 4625     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-on-stack/11")
 4626     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"  "F - test-convert-length-of-array-on-stack/12")
 4627     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-on-stack/13")
 4628     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-on-stack/14")
 4629     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-on-stack/15")
 4630     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-on-stack/16")
 4631     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-on-stack/17")
 4632     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-on-stack/18")
 4633     # . epilogue
 4634     89/<- %esp 5/r32/ebp
 4635     5d/pop-to-ebp
 4636     c3/return
 4637 
 4638 test-reg-var-def-with-read-of-same-register:
 4639     # . prologue
 4640     55/push-ebp
 4641     89/<- %ebp 4/r32/esp
 4642     # setup
 4643     (clear-stream _test-input-stream)
 4644     (clear-stream $_test-input-buffered-file->buffer)
 4645     (clear-stream _test-output-stream)
 4646     (clear-stream $_test-output-buffered-file->buffer)
 4647     (clear-stream _test-error-stream)
 4648     (clear-stream $_test-error-buffered-file->buffer)
 4649     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)  # bytes of args in call to convert-mu
 4650     68/push 0/imm32
 4651     68/push 0/imm32
 4652     89/<- %edx 4/r32/esp
 4653     (tailor-exit-descriptor %edx 0x10)
 4654     #
 4655     (write _test-input-stream "fn foo {\n")
 4656     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4657     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4658     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 4659     (write _test-input-stream "}\n")
 4660     # convert
 4661     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 4662     # registers except esp could be clobbered at this point (though they shouldn't be)
 4663     # restore ed
 4664     89/<- %edx 4/r32/esp
 4665     (flush _test-output-buffered-file)
 4666     (flush _test-error-buffered-file)
 4667 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4673 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4679     (check-stream-equal _test-error-stream  ""  "F - test-reg-var-def-with-read-of-same-register: error stream should be empty")
 4680     # check output
 4681     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-reg-var-def-with-read-of-same-register/0")
 4682     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-reg-var-def-with-read-of-same-register/1")
 4683     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-reg-var-def-with-read-of-same-register/2")
 4684     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-reg-var-def-with-read-of-same-register/3")
 4685     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-reg-var-def-with-read-of-same-register/4")
 4686     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-reg-var-def-with-read-of-same-register/5")
 4687     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-reg-var-def-with-read-of-same-register/6")
 4688     (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")
 4689     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-reg-var-def-with-read-of-same-register/8")
 4690     (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")
 4691     (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")
 4692     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-reg-var-def-with-read-of-same-register/13")
 4693     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-reg-var-def-with-read-of-same-register/14")
 4694     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-reg-var-def-with-read-of-same-register/15")
 4695     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-reg-var-def-with-read-of-same-register/16")
 4696     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-reg-var-def-with-read-of-same-register/17")
 4697     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-reg-var-def-with-read-of-same-register/18")
 4698     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-reg-var-def-with-read-of-same-register/19")
 4699     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-reg-var-def-with-read-of-same-register/20")
 4700     # don't restore from ebp
 4701     81 0/subop/add %esp 8/imm32
 4702     # . epilogue
 4703     5d/pop-to-ebp
 4704     c3/return
 4705 
 4706 test-convert-index-into-array:
 4707     # . prologue
 4708     55/push-ebp
 4709     89/<- %ebp 4/r32/esp
 4710     # setup
 4711     (clear-stream _test-input-stream)
 4712     (clear-stream $_test-input-buffered-file->buffer)
 4713     (clear-stream _test-output-stream)
 4714     (clear-stream $_test-output-buffered-file->buffer)
 4715     #
 4716     (write _test-input-stream "fn foo {\n")
 4717     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4718     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4719     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 4720     (write _test-input-stream "}\n")
 4721     # convert
 4722     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4723     (flush _test-output-buffered-file)
 4724 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4730     # check output
 4731     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array/0")
 4732     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array/1")
 4733     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array/2")
 4734     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array/3")
 4735     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array/4")
 4736     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array/5")
 4737     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array/6")
 4738     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array/7")
 4739     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array/8")
 4740     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array/9")
 4741     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx<<0x00000002 + 4) 0x00000000/r32"  "F - test-convert-index-into-array/10")
 4742     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array/11")
 4743     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array/12")
 4744     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array/13")
 4745     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array/14")
 4746     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array/15")
 4747     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array/16")
 4748     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array/17")
 4749     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array/18")
 4750     # . epilogue
 4751     89/<- %esp 5/r32/ebp
 4752     5d/pop-to-ebp
 4753     c3/return
 4754 
 4755 test-convert-index-into-array-of-bytes:
 4756     # . prologue
 4757     55/push-ebp
 4758     89/<- %ebp 4/r32/esp
 4759     # setup
 4760     (clear-stream _test-input-stream)
 4761     (clear-stream $_test-input-buffered-file->buffer)
 4762     (clear-stream _test-output-stream)
 4763     (clear-stream $_test-output-buffered-file->buffer)
 4764     #
 4765     (write _test-input-stream "fn foo {\n")
 4766     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4767     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4768     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, idx\n")
 4769     (write _test-input-stream "}\n")
 4770     # convert
 4771     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4772     (flush _test-output-buffered-file)
 4773 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4779     # check output
 4780     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes/0")
 4781     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes/1")
 4782     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes/2")
 4783     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes/3")
 4784     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes/4")
 4785     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes/5")
 4786     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes/6")
 4787     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-of-bytes/7")
 4788     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes/8")
 4789     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-of-bytes/9")
 4790     (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")
 4791     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes/13")
 4792     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes/14")
 4793     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes/15")
 4794     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes/16")
 4795     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes/17")
 4796     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes/18")
 4797     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes/19")
 4798     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes/20")
 4799     # . epilogue
 4800     89/<- %esp 5/r32/ebp
 4801     5d/pop-to-ebp
 4802     c3/return
 4803 
 4804 test-convert-index-into-array-with-literal:
 4805     # . prologue
 4806     55/push-ebp
 4807     89/<- %ebp 4/r32/esp
 4808     # setup
 4809     (clear-stream _test-input-stream)
 4810     (clear-stream $_test-input-buffered-file->buffer)
 4811     (clear-stream _test-output-stream)
 4812     (clear-stream $_test-output-buffered-file->buffer)
 4813     #
 4814     (write _test-input-stream "fn foo {\n")
 4815     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4816     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
 4817     (write _test-input-stream "}\n")
 4818     # convert
 4819     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4820     (flush _test-output-buffered-file)
 4821 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4827     # check output
 4828     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-with-literal/0")
 4829     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-with-literal/1")
 4830     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-with-literal/2")
 4831     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-with-literal/3")
 4832     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-with-literal/4")
 4833     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-with-literal/5")
 4834     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-with-literal/6")
 4835     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-with-literal/7")
 4836                                                                                  # 2 * 4 bytes/elem + 4 bytes for size = offset 12
 4837     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x0000000c) 0x00000000/r32"  "F - test-convert-index-into-array-with-literal/8")
 4838     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-with-literal/9")
 4839     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-with-literal/10")
 4840     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-with-literal/11")
 4841     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-with-literal/12")
 4842     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-with-literal/13")
 4843     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-with-literal/14")
 4844     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-with-literal/15")
 4845     # . epilogue
 4846     89/<- %esp 5/r32/ebp
 4847     5d/pop-to-ebp
 4848     c3/return
 4849 
 4850 test-convert-index-into-array-of-bytes-with-literal:
 4851     # . prologue
 4852     55/push-ebp
 4853     89/<- %ebp 4/r32/esp
 4854     # setup
 4855     (clear-stream _test-input-stream)
 4856     (clear-stream $_test-input-buffered-file->buffer)
 4857     (clear-stream _test-output-stream)
 4858     (clear-stream $_test-output-buffered-file->buffer)
 4859     #
 4860     (write _test-input-stream "fn foo {\n")
 4861     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4862     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, 2\n")
 4863     (write _test-input-stream "}\n")
 4864     # convert
 4865     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4866     (flush _test-output-buffered-file)
 4867 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4873     # check output
 4874     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-with-literal/0")
 4875     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-with-literal/1")
 4876     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-with-literal/2")
 4877     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-with-literal/3")
 4878     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-with-literal/4")
 4879     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-with-literal/5")
 4880     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-with-literal/6")
 4881     (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")
 4882                                                                                  # 2 * 1 byte/elem + 4 bytes for size = offset 6
 4883     (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")
 4884     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-with-literal/9")
 4885     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-with-literal/10")
 4886     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-with-literal/11")
 4887     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-with-literal/12")
 4888     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-with-literal/13")
 4889     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-with-literal/14")
 4890     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-with-literal/15")
 4891     # . epilogue
 4892     89/<- %esp 5/r32/ebp
 4893     5d/pop-to-ebp
 4894     c3/return
 4895 
 4896 test-convert-index-into-array-on-stack:
 4897     # . prologue
 4898     55/push-ebp
 4899     89/<- %ebp 4/r32/esp
 4900     # setup
 4901     (clear-stream _test-input-stream)
 4902     (clear-stream $_test-input-buffered-file->buffer)
 4903     (clear-stream _test-output-stream)
 4904     (clear-stream $_test-output-buffered-file->buffer)
 4905     #
 4906     (write _test-input-stream "fn foo {\n")
 4907     (write _test-input-stream "  var arr: (array int 3)\n")
 4908     (write _test-input-stream "  var idx/eax: int <- copy 2\n")
 4909     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 4910     (write _test-input-stream "}\n")
 4911     # convert
 4912     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4913     (flush _test-output-buffered-file)
 4914 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4920     # check output
 4921     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack/0")
 4922     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack/1")
 4923     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack/2")
 4924     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack/3")
 4925     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack/4")
 4926     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack/5")
 4927     # var arr
 4928     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack/6")
 4929     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack/7")
 4930     # var idx
 4931     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack/8")
 4932     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 2/imm32"                  "F - test-convert-index-into-array-on-stack/9")
 4933     # var x is at (ebp-0x10) + idx<<2 + 4 = ebp + idx<<2 - 0xc
 4934     (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")
 4935     # reclaim idx
 4936     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack/11")
 4937     # reclaim arr
 4938     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"    "F - test-convert-index-into-array-on-stack/12")
 4939     #
 4940     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack/13")
 4941     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack/14")
 4942     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack/15")
 4943     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack/16")
 4944     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack/17")
 4945     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack/18")
 4946     # . epilogue
 4947     89/<- %esp 5/r32/ebp
 4948     5d/pop-to-ebp
 4949     c3/return
 4950 
 4951 test-convert-index-into-array-on-stack-with-literal:
 4952     # . prologue
 4953     55/push-ebp
 4954     89/<- %ebp 4/r32/esp
 4955     # setup
 4956     (clear-stream _test-input-stream)
 4957     (clear-stream $_test-input-buffered-file->buffer)
 4958     (clear-stream _test-output-stream)
 4959     (clear-stream $_test-output-buffered-file->buffer)
 4960     #
 4961     (write _test-input-stream "fn foo {\n")
 4962     (write _test-input-stream "  var arr: (array int 3)\n")
 4963     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
 4964     (write _test-input-stream "}\n")
 4965     # convert
 4966     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4967     (flush _test-output-buffered-file)
 4968 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4974     # check output
 4975     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack-with-literal/0")
 4976     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack-with-literal/1")
 4977     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack-with-literal/2")
 4978     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack-with-literal/3")
 4979     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack-with-literal/4")
 4980     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack-with-literal/5")
 4981     # var arr
 4982     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack-with-literal/6")
 4983     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack-with-literal/7")
 4984     # var x
 4985     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack-with-literal/8")
 4986     # x is at (ebp-0x10) + 4 + 2*4 = ebp-4
 4987     (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")
 4988     # reclaim x
 4989     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack-with-literal/10")
 4990     # reclaim arr
 4991     (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")
 4992     #
 4993     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack-with-literal/12")
 4994     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack-with-literal/13")
 4995     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack-with-literal/14")
 4996     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack-with-literal/15")
 4997     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack-with-literal/16")
 4998     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack-with-literal/17")
 4999     # . epilogue
 5000     89/<- %esp 5/r32/ebp
 5001     5d/pop-to-ebp
 5002     c3/return
 5003 
 5004 test-convert-index-into-array-of-bytes-on-stack-with-literal:
 5005     # . prologue
 5006     55/push-ebp
 5007     89/<- %ebp 4/r32/esp
 5008     # setup
 5009     (clear-stream _test-input-stream)
 5010     (clear-stream $_test-input-buffered-file->buffer)
 5011     (clear-stream _test-output-stream)
 5012     (clear-stream $_test-output-buffered-file->buffer)
 5013     #
 5014     (write _test-input-stream "fn foo {\n")
 5015     (write _test-input-stream "  var arr: (array byte 3)\n")
 5016     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, 2\n")
 5017     (write _test-input-stream "}\n")
 5018     # convert
 5019     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5020     (flush _test-output-buffered-file)
 5021 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5027     # check output
 5028     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/0")
 5029     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/1")
 5030     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/2")
 5031     (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")
 5032     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/4")
 5033     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/5")
 5034     # var arr
 5035     (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")
 5036     (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")
 5037     # var x
 5038     (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")
 5039     # x is at (ebp-7) + 4 + 2 = ebp-1
 5040     (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")
 5041     # reclaim x
 5042     (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")
 5043     # reclaim arr
 5044     (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")
 5045     #
 5046     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/12")
 5047     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/13")
 5048     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/14")
 5049     (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")
 5050     (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")
 5051     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/17")
 5052     # . epilogue
 5053     89/<- %esp 5/r32/ebp
 5054     5d/pop-to-ebp
 5055     c3/return
 5056 
 5057 test-convert-index-into-array-using-offset:
 5058     # . prologue
 5059     55/push-ebp
 5060     89/<- %ebp 4/r32/esp
 5061     # setup
 5062     (clear-stream _test-input-stream)
 5063     (clear-stream $_test-input-buffered-file->buffer)
 5064     (clear-stream _test-output-stream)
 5065     (clear-stream $_test-output-buffered-file->buffer)
 5066     #
 5067     (write _test-input-stream "fn foo {\n")
 5068     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 5069     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 5070     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
 5071     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
 5072     (write _test-input-stream "}\n")
 5073     # convert
 5074     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5075     (flush _test-output-buffered-file)
 5076 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5082     # check output
 5083     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset/0")
 5084     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset/1")
 5085     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset/2")
 5086     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset/3")
 5087     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset/4")
 5088     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset/5")
 5089     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset/6")
 5090     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-using-offset/7")
 5091     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset/8")
 5092     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-using-offset/9")
 5093     (check-next-stream-line-equal _test-output-stream "    69/multiply %ecx 0x00000004/imm32 0x00000001/r32"  "F - test-convert-index-into-array-using-offset/10")
 5094     (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")
 5095     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset/12")
 5096     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset/13")
 5097     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset/14")
 5098     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset/15")
 5099     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset/16")
 5100     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset/17")
 5101     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset/18")
 5102     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset/19")
 5103     # . epilogue
 5104     89/<- %esp 5/r32/ebp
 5105     5d/pop-to-ebp
 5106     c3/return
 5107 
 5108 test-convert-index-into-array-of-bytes-using-offset:
 5109     # . prologue
 5110     55/push-ebp
 5111     89/<- %ebp 4/r32/esp
 5112     # setup
 5113     (clear-stream _test-input-stream)
 5114     (clear-stream $_test-input-buffered-file->buffer)
 5115     (clear-stream _test-output-stream)
 5116     (clear-stream $_test-output-buffered-file->buffer)
 5117     #
 5118     (write _test-input-stream "fn foo {\n")
 5119     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 5120     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 5121     (write _test-input-stream "  var off/ecx: (offset byte) <- compute-offset arr, idx\n")
 5122     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, off\n")
 5123     (write _test-input-stream "}\n")
 5124     # convert
 5125     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5126     (flush _test-output-buffered-file)
 5127 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5133     # check output
 5134     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-using-offset/0")
 5135     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-using-offset/1")
 5136     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-using-offset/2")
 5137     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-using-offset/3")
 5138     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-using-offset/4")
 5139     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-using-offset/5")
 5140     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-using-offset/6")
 5141     (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")
 5142     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes-using-offset/8")
 5143     (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")
 5144     (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")
 5145     (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")
 5146     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes-using-offset/12")
 5147     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-using-offset/13")
 5148     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-using-offset/14")
 5149     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-using-offset/15")
 5150     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-using-offset/16")
 5151     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-using-offset/17")
 5152     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-using-offset/18")
 5153     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-using-offset/19")
 5154     # . epilogue
 5155     89/<- %esp 5/r32/ebp
 5156     5d/pop-to-ebp
 5157     c3/return
 5158 
 5159 test-convert-index-into-array-using-offset-on-stack:
 5160     # . prologue
 5161     55/push-ebp
 5162     89/<- %ebp 4/r32/esp
 5163     # setup
 5164     (clear-stream _test-input-stream)
 5165     (clear-stream $_test-input-buffered-file->buffer)
 5166     (clear-stream _test-output-stream)
 5167     (clear-stream $_test-output-buffered-file->buffer)
 5168     #
 5169     (write _test-input-stream "fn foo {\n")
 5170     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 5171     (write _test-input-stream "  var idx: int\n")
 5172     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
 5173     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
 5174     (write _test-input-stream "}\n")
 5175     # convert
 5176     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5177     (flush _test-output-buffered-file)
 5178 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5184     # check output
 5185     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset-on-stack/0")
 5186     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset-on-stack/1")
 5187     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset-on-stack/2")
 5188     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset-on-stack/3")
 5189     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset-on-stack/4")
 5190     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset-on-stack/5")
 5191     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset-on-stack/6")
 5192     (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")
 5193     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"                         "F - test-convert-index-into-array-using-offset-on-stack/8")
 5194     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset-on-stack/9")
 5195     (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")
 5196     (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")
 5197     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset-on-stack/12")
 5198     (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")
 5199     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset-on-stack/14")
 5200     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset-on-stack/15")
 5201     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset-on-stack/16")
 5202     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset-on-stack/17")
 5203     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset-on-stack/18")
 5204     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset-on-stack/19")
 5205     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset-on-stack/20")
 5206     # . epilogue
 5207     89/<- %esp 5/r32/ebp
 5208     5d/pop-to-ebp
 5209     c3/return
 5210 
 5211 test-convert-index-into-array-of-bytes-using-offset-on-stack:
 5212     # . prologue
 5213     55/push-ebp
 5214     89/<- %ebp 4/r32/esp
 5215     # setup
 5216     (clear-stream _test-input-stream)
 5217     (clear-stream $_test-input-buffered-file->buffer)
 5218     (clear-stream _test-output-stream)
 5219     (clear-stream $_test-output-buffered-file->buffer)
 5220     #
 5221     (write _test-input-stream "fn foo {\n")
 5222     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 5223     (write _test-input-stream "  var idx: int\n")
 5224     (write _test-input-stream "  var off/ecx: (offset byte) <- compute-offset arr, idx\n")
 5225     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, off\n")
 5226     (write _test-input-stream "}\n")
 5227     # convert
 5228     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5229     (flush _test-output-buffered-file)
 5230 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5236     # check output
 5237     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/0")
 5238     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/1")
 5239     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/2")
 5240     (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")
 5241     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/4")
 5242     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/5")
 5243     (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")
 5244     (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")
 5245     (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")
 5246     (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")
 5247     (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")
 5248     (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")
 5249     (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")
 5250     (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")
 5251     (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")
 5252     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/15")
 5253     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/16")
 5254     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/17")
 5255     (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")
 5256     (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")
 5257     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/20")
 5258     # . epilogue
 5259     89/<- %esp 5/r32/ebp
 5260     5d/pop-to-ebp
 5261     c3/return
 5262 
 5263 test-convert-function-and-type-definition:
 5264     # . prologue
 5265     55/push-ebp
 5266     89/<- %ebp 4/r32/esp
 5267     # setup
 5268     (clear-stream _test-input-stream)
 5269     (clear-stream $_test-input-buffered-file->buffer)
 5270     (clear-stream _test-output-stream)
 5271     (clear-stream $_test-output-buffered-file->buffer)
 5272     #
 5273     (write _test-input-stream "fn foo a: (addr t) {\n")
 5274     (write _test-input-stream "  var _a/eax: (addr t) <- copy a\n")
 5275     (write _test-input-stream "  var b/ecx: (addr int) <- get _a, x\n")
 5276     (write _test-input-stream "  var c/ecx: (addr int) <- get _a, y\n")
 5277     (write _test-input-stream "}\n")
 5278     (write _test-input-stream "type t {\n")
 5279     (write _test-input-stream "  x: int\n")
 5280     (write _test-input-stream "  y: int\n")
 5281     (write _test-input-stream "}\n")
 5282     # convert
 5283     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5284     (flush _test-output-buffered-file)
 5285 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5291     # check output
 5292     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-and-type-definition/0")
 5293     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-and-type-definition/1")
 5294     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-and-type-definition/2")
 5295     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-and-type-definition/3")
 5296     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-and-type-definition/4")
 5297     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-and-type-definition/5")
 5298     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-function-and-type-definition/6")
 5299     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-and-type-definition/7")
 5300     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-and-type-definition/8")
 5301     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000000) 0x00000001/r32"  "F - test-convert-function-and-type-definition/9")
 5302     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000004) 0x00000001/r32"  "F - test-convert-function-and-type-definition/11")
 5303     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-and-type-definition/13")
 5304     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-convert-function-and-type-definition/14")
 5305     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-and-type-definition/15")
 5306     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-and-type-definition/16")
 5307     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-and-type-definition/17")
 5308     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-and-type-definition/18")
 5309     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-and-type-definition/19")
 5310     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-and-type-definition/20")
 5311     # . epilogue
 5312     89/<- %esp 5/r32/ebp
 5313     5d/pop-to-ebp
 5314     c3/return
 5315 
 5316 test-type-definition-with-array:
 5317     # . prologue
 5318     55/push-ebp
 5319     89/<- %ebp 4/r32/esp
 5320     # setup
 5321     (clear-stream _test-input-stream)
 5322     (clear-stream $_test-input-buffered-file->buffer)
 5323     (clear-stream _test-output-stream)
 5324     (clear-stream $_test-output-buffered-file->buffer)
 5325     (clear-stream _test-error-stream)
 5326     (clear-stream $_test-error-buffered-file->buffer)
 5327     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5328     68/push 0/imm32
 5329     68/push 0/imm32
 5330     89/<- %edx 4/r32/esp
 5331     (tailor-exit-descriptor %edx 0x10)
 5332     #
 5333     (write _test-input-stream "type t {\n")
 5334     (write _test-input-stream "  a: (array int 3)\n")
 5335     (write _test-input-stream "}\n")
 5336     # convert
 5337     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5338     # registers except esp clobbered at this point
 5339     # restore ed
 5340     89/<- %edx 4/r32/esp
 5341     (flush _test-output-buffered-file)
 5342     (flush _test-error-buffered-file)
 5343 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5349     # check output
 5350     (check-stream-equal _test-output-stream  ""  "F - test-type-definition-with-array: output should be empty")
 5351     (check-next-stream-line-equal _test-error-stream  "type t: 'array' elements not allowed for now"  "F - test-type-definition-with-array: error message")
 5352     # check that stop(1) was called
 5353     (check-ints-equal *(edx+4) 2 "F - test-type-definition-with-array: exit status")
 5354     # don't restore from ebp
 5355     81 0/subop/add %esp 8/imm32
 5356     # . epilogue
 5357     5d/pop-to-ebp
 5358     c3/return
 5359 
 5360 test-type-definition-with-addr:
 5361     # . prologue
 5362     55/push-ebp
 5363     89/<- %ebp 4/r32/esp
 5364     # setup
 5365     (clear-stream _test-input-stream)
 5366     (clear-stream $_test-input-buffered-file->buffer)
 5367     (clear-stream _test-output-stream)
 5368     (clear-stream $_test-output-buffered-file->buffer)
 5369     (clear-stream _test-error-stream)
 5370     (clear-stream $_test-error-buffered-file->buffer)
 5371     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5372     68/push 0/imm32
 5373     68/push 0/imm32
 5374     89/<- %edx 4/r32/esp
 5375     (tailor-exit-descriptor %edx 0x10)
 5376     #
 5377     (write _test-input-stream "type t {\n")
 5378     (write _test-input-stream "  a: (addr int)\n")
 5379     (write _test-input-stream "}\n")
 5380     # convert
 5381     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5382     # registers except esp clobbered at this point
 5383     # restore ed
 5384     89/<- %edx 4/r32/esp
 5385     (flush _test-output-buffered-file)
 5386     (flush _test-error-buffered-file)
 5387 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5393     # check output
 5394     (check-stream-equal _test-output-stream  ""  "F - test-type-definition-with-addr: output should be empty")
 5395     (check-next-stream-line-equal _test-error-stream  "type t: 'addr' elements not allowed"  "F - test-type-definition-with-addr: error message")
 5396     # check that stop(1) was called
 5397     (check-ints-equal *(edx+4) 2 "F - test-type-definition-with-addr: exit status")
 5398     # don't restore from ebp
 5399     81 0/subop/add %esp 8/imm32
 5400     # . epilogue
 5401     5d/pop-to-ebp
 5402     c3/return
 5403 
 5404 test-convert-function-with-local-var-with-user-defined-type:
 5405     # . prologue
 5406     55/push-ebp
 5407     89/<- %ebp 4/r32/esp
 5408     # setup
 5409     (clear-stream _test-input-stream)
 5410     (clear-stream $_test-input-buffered-file->buffer)
 5411     (clear-stream _test-output-stream)
 5412     (clear-stream $_test-output-buffered-file->buffer)
 5413     #
 5414     (write _test-input-stream "fn foo {\n")
 5415     (write _test-input-stream "  var a: t\n")
 5416     (write _test-input-stream "}\n")
 5417     (write _test-input-stream "type t {\n")
 5418     (write _test-input-stream "  x: int\n")
 5419     (write _test-input-stream "  y: int\n")
 5420     (write _test-input-stream "}\n")
 5421     # convert
 5422     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5423     (flush _test-output-buffered-file)
 5424 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5430     # check output
 5431     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-user-defined-type/0")
 5432     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-user-defined-type/1")
 5433     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-user-defined-type/2")
 5434     (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")
 5435     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-user-defined-type/4")
 5436     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-user-defined-type/5")
 5437     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/6")
 5438     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/7")
 5439     (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")
 5440     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-user-defined-type/9")
 5441     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-user-defined-type/10")
 5442     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-user-defined-type/11")
 5443     (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")
 5444     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-with-user-defined-type/13")
 5445     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-user-defined-type/14")
 5446     # . epilogue
 5447     89/<- %esp 5/r32/ebp
 5448     5d/pop-to-ebp
 5449     c3/return
 5450 
 5451 test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type:
 5452     # . prologue
 5453     55/push-ebp
 5454     89/<- %ebp 4/r32/esp
 5455     # setup
 5456     (clear-stream _test-input-stream)
 5457     (clear-stream $_test-input-buffered-file->buffer)
 5458     (clear-stream _test-output-stream)
 5459     (clear-stream $_test-output-buffered-file->buffer)
 5460     #
 5461     (write _test-input-stream "fn foo {\n")
 5462     (write _test-input-stream "  var a: t\n")
 5463     (write _test-input-stream "}\n")
 5464     (write _test-input-stream "type t {\n")
 5465     (write _test-input-stream "  x: s\n")
 5466     (write _test-input-stream "}\n")
 5467     (write _test-input-stream "type s {\n")
 5468     (write _test-input-stream "  z: int\n")
 5469     (write _test-input-stream "}\n")
 5470     # convert
 5471     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5472     (flush _test-output-buffered-file)
 5473 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5479     # check output
 5480     (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")
 5481     (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")
 5482     (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")
 5483     (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")
 5484     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/4")
 5485     (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")
 5486     (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")
 5487     (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")
 5488     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/9")
 5489     (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")
 5490     (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")
 5491     (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")
 5492     (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")
 5493     (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")
 5494     # . epilogue
 5495     89/<- %esp 5/r32/ebp
 5496     5d/pop-to-ebp
 5497     c3/return
 5498 
 5499 test-convert-function-call-with-arg-of-user-defined-type:
 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     #
 5509     (write _test-input-stream "fn f {\n")
 5510     (write _test-input-stream "  var a: t\n")
 5511     (write _test-input-stream "  foo a\n")
 5512     (write _test-input-stream "}\n")
 5513     (write _test-input-stream "fn foo x: t {\n")
 5514     (write _test-input-stream "}\n")
 5515     (write _test-input-stream "type t {\n")
 5516     (write _test-input-stream "  x: int\n")
 5517     (write _test-input-stream "  y: int\n")
 5518     (write _test-input-stream "}\n")
 5519     # convert
 5520     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5521     (flush _test-output-buffered-file)
 5522 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5528     # check output
 5529     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
 5530     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
 5531     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
 5532     (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")
 5533     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
 5534     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
 5535     # var a: t
 5536     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/6")
 5537     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/7")
 5538     # foo a
 5539     (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")
 5540     #
 5541     (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")
 5542     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
 5543     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
 5544     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
 5545     (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")
 5546     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
 5547     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
 5548     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
 5549     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
 5550     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
 5551     (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")
 5552     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
 5553     (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")
 5554     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
 5555     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
 5556     # . epilogue
 5557     89/<- %esp 5/r32/ebp
 5558     5d/pop-to-ebp
 5559     c3/return
 5560 
 5561 test-convert-function-call-with-arg-of-user-defined-type-register-indirect:
 5562     # . prologue
 5563     55/push-ebp
 5564     89/<- %ebp 4/r32/esp
 5565     # setup
 5566     (clear-stream _test-input-stream)
 5567     (clear-stream $_test-input-buffered-file->buffer)
 5568     (clear-stream _test-output-stream)
 5569     (clear-stream $_test-output-buffered-file->buffer)
 5570     #
 5571     (write _test-input-stream "fn f {\n")
 5572     (write _test-input-stream "  var a/eax: (addr t) <- copy 0\n")
 5573     (write _test-input-stream "  foo *a\n")
 5574     (write _test-input-stream "}\n")
 5575     (write _test-input-stream "fn foo x: t {\n")
 5576     (write _test-input-stream "}\n")
 5577     (write _test-input-stream "type t {\n")
 5578     (write _test-input-stream "  x: int\n")
 5579     (write _test-input-stream "  y: int\n")
 5580     (write _test-input-stream "}\n")
 5581     # convert
 5582     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5583     (flush _test-output-buffered-file)
 5584 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5590     # check output
 5591     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
 5592     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
 5593     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
 5594     (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")
 5595     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
 5596     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
 5597     # var a
 5598     (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")
 5599     (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")
 5600     # foo a
 5601     (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")
 5602     #
 5603     (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")
 5604     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
 5605     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
 5606     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
 5607     (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")
 5608     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
 5609     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
 5610     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
 5611     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
 5612     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
 5613     (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")
 5614     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
 5615     (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")
 5616     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
 5617     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
 5618     # . epilogue
 5619     89/<- %esp 5/r32/ebp
 5620     5d/pop-to-ebp
 5621     c3/return
 5622 
 5623 # we don't have special support for call-by-reference; just explicitly create
 5624 # a new variable with the address of the arg
 5625 test-convert-function-call-with-arg-of-user-defined-type-by-reference:
 5626     # . prologue
 5627     55/push-ebp
 5628     89/<- %ebp 4/r32/esp
 5629     # setup
 5630     (clear-stream _test-input-stream)
 5631     (clear-stream $_test-input-buffered-file->buffer)
 5632     (clear-stream _test-output-stream)
 5633     (clear-stream $_test-output-buffered-file->buffer)
 5634     #
 5635     (write _test-input-stream "fn f {\n")
 5636     (write _test-input-stream "  var a: t\n")
 5637     (write _test-input-stream "  var b/eax: (addr t) <- address a\n")
 5638     (write _test-input-stream "  foo b\n")
 5639     (write _test-input-stream "}\n")
 5640     (write _test-input-stream "fn foo x: (addr t) {\n")
 5641     (write _test-input-stream "  var x/ecx: (addr int) <- copy x\n")
 5642     (write _test-input-stream "  increment *x\n")
 5643     (write _test-input-stream "}\n")
 5644     (write _test-input-stream "type t {\n")
 5645     (write _test-input-stream "  x: int\n")
 5646     (write _test-input-stream "  y: int\n")
 5647     (write _test-input-stream "}\n")
 5648     # convert
 5649     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5650     (flush _test-output-buffered-file)
 5651 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5657     # check output
 5658     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/0")
 5659     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/1")
 5660     (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")
 5661     (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")
 5662     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/4")
 5663     (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")
 5664     # var a: t
 5665     (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")
 5666     (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")
 5667     # var b/eax: (addr t)
 5668     (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")
 5669     (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")
 5670     # foo a
 5671     (check-next-stream-line-equal _test-output-stream "    (foo %eax)"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/10")
 5672     #
 5673     (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")
 5674     (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")
 5675     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/13")
 5676     (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")
 5677     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/15")
 5678     (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")
 5679     (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")
 5680     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/18")
 5681     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/19")
 5682     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/20")
 5683     (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")
 5684     (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")
 5685     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/23")
 5686     (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")
 5687     (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")
 5688     (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")
 5689     (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")
 5690     (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")
 5691     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/29")
 5692     (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")
 5693     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/31")
 5694     (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")
 5695     (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")
 5696     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/34")
 5697     # . epilogue
 5698     89/<- %esp 5/r32/ebp
 5699     5d/pop-to-ebp
 5700     c3/return
 5701 
 5702 test-convert-get-on-local-variable:
 5703     # . prologue
 5704     55/push-ebp
 5705     89/<- %ebp 4/r32/esp
 5706     # setup
 5707     (clear-stream _test-input-stream)
 5708     (clear-stream $_test-input-buffered-file->buffer)
 5709     (clear-stream _test-output-stream)
 5710     (clear-stream $_test-output-buffered-file->buffer)
 5711     #
 5712     (write _test-input-stream "fn foo {\n")
 5713     (write _test-input-stream "  var a: t\n")
 5714     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5715     (write _test-input-stream "}\n")
 5716     (write _test-input-stream "type t {\n")
 5717     (write _test-input-stream "  x: int\n")
 5718     (write _test-input-stream "  y: int\n")
 5719     (write _test-input-stream "}\n")
 5720     # convert
 5721     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5722     (flush _test-output-buffered-file)
 5723 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5729     # check output
 5730     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-local-variable/0")
 5731     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-local-variable/1")
 5732     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-local-variable/2")
 5733     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-local-variable/3")
 5734     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-local-variable/4")
 5735     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-local-variable/5")
 5736     # var a
 5737     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/6")
 5738     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/7")
 5739     # var c
 5740     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-local-variable/8")
 5741     # get
 5742     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000001/r32"  "F - test-convert-get-on-local-variable/9")
 5743     # reclaim c
 5744     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-local-variable/10")
 5745     # reclaim a
 5746     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000008/imm32"  "F - test-convert-get-on-local-variable/11")
 5747     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-local-variable/12")
 5748     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-local-variable/13")
 5749     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-local-variable/14")
 5750     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-local-variable/15")
 5751     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-local-variable/16")
 5752     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-local-variable/17")
 5753     # . epilogue
 5754     89/<- %esp 5/r32/ebp
 5755     5d/pop-to-ebp
 5756     c3/return
 5757 
 5758 test-convert-get-on-function-argument:
 5759     # . prologue
 5760     55/push-ebp
 5761     89/<- %ebp 4/r32/esp
 5762     # setup
 5763     (clear-stream _test-input-stream)
 5764     (clear-stream $_test-input-buffered-file->buffer)
 5765     (clear-stream _test-output-stream)
 5766     (clear-stream $_test-output-buffered-file->buffer)
 5767     #
 5768     (write _test-input-stream "fn foo a: t {\n")
 5769     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5770     (write _test-input-stream "}\n")
 5771     (write _test-input-stream "type t {\n")
 5772     (write _test-input-stream "  x: int\n")
 5773     (write _test-input-stream "  y: int\n")
 5774     (write _test-input-stream "}\n")
 5775     # convert
 5776     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5777     (flush _test-output-buffered-file)
 5778 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5784     # check output
 5785     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument/0")
 5786     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument/1")
 5787     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument/2")
 5788     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument/3")
 5789     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument/4")
 5790     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument/5")
 5791     # var c
 5792     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument/6")
 5793     # get
 5794     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0x0000000c) 0x00000001/r32"  "F - test-convert-get-on-function-argument/7")
 5795     # reclaim c
 5796     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument/8")
 5797     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument/9")
 5798     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument/10")
 5799     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument/11")
 5800     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument/12")
 5801     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument/13")
 5802     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument/14")
 5803     # . epilogue
 5804     89/<- %esp 5/r32/ebp
 5805     5d/pop-to-ebp
 5806     c3/return
 5807 
 5808 test-convert-get-on-function-argument-with-known-type:
 5809     # . prologue
 5810     55/push-ebp
 5811     89/<- %ebp 4/r32/esp
 5812     # setup
 5813     (clear-stream _test-input-stream)
 5814     (clear-stream $_test-input-buffered-file->buffer)
 5815     (clear-stream _test-output-stream)
 5816     (clear-stream $_test-output-buffered-file->buffer)
 5817     #
 5818     (write _test-input-stream "type t {\n")
 5819     (write _test-input-stream "  x: int\n")
 5820     (write _test-input-stream "  y: int\n")
 5821     (write _test-input-stream "}\n")
 5822     (write _test-input-stream "fn foo a: t {\n")
 5823     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5824     (write _test-input-stream "}\n")
 5825     # convert
 5826     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5827     (flush _test-output-buffered-file)
 5828 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5834     # check output
 5835     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument-with-known-type/0")
 5836     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument-with-known-type/1")
 5837     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument-with-known-type/2")
 5838     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument-with-known-type/3")
 5839     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument-with-known-type/4")
 5840     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument-with-known-type/5")
 5841     # var c
 5842     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument-with-known-type/6")
 5843     # get
 5844     (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")
 5845     # reclaim c
 5846     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument-with-known-type/8")
 5847     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument-with-known-type/9")
 5848     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument-with-known-type/10")
 5849     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument-with-known-type/11")
 5850     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument-with-known-type/12")
 5851     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument-with-known-type/13")
 5852     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument-with-known-type/14")
 5853     # . epilogue
 5854     89/<- %esp 5/r32/ebp
 5855     5d/pop-to-ebp
 5856     c3/return
 5857 
 5858 test-add-with-too-many-inouts:
 5859     # . prologue
 5860     55/push-ebp
 5861     89/<- %ebp 4/r32/esp
 5862     # setup
 5863     (clear-stream _test-input-stream)
 5864     (clear-stream $_test-input-buffered-file->buffer)
 5865     (clear-stream _test-output-stream)
 5866     (clear-stream $_test-output-buffered-file->buffer)
 5867     (clear-stream _test-error-stream)
 5868     (clear-stream $_test-error-buffered-file->buffer)
 5869     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5870     68/push 0/imm32
 5871     68/push 0/imm32
 5872     89/<- %edx 4/r32/esp
 5873     (tailor-exit-descriptor %edx 0x10)
 5874     #
 5875     (write _test-input-stream "fn foo {\n")
 5876     (write _test-input-stream "  var a: int\n")
 5877     (write _test-input-stream "  var b/ecx: int <- add a, 0\n")
 5878     (write _test-input-stream "}\n")
 5879     # convert
 5880     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5881     # registers except esp clobbered at this point
 5882     # restore ed
 5883     89/<- %edx 4/r32/esp
 5884     (flush _test-output-buffered-file)
 5885     (flush _test-error-buffered-file)
 5886 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5892     # check output
 5893     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-inouts: output should be empty")
 5894     (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")
 5895     # check that stop(1) was called
 5896     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-inouts: exit status")
 5897     # don't restore from ebp
 5898     81 0/subop/add %esp 8/imm32
 5899     # . epilogue
 5900     5d/pop-to-ebp
 5901     c3/return
 5902 
 5903 test-add-with-too-many-inouts-2:
 5904     # . prologue
 5905     55/push-ebp
 5906     89/<- %ebp 4/r32/esp
 5907     # setup
 5908     (clear-stream _test-input-stream)
 5909     (clear-stream $_test-input-buffered-file->buffer)
 5910     (clear-stream _test-output-stream)
 5911     (clear-stream $_test-output-buffered-file->buffer)
 5912     (clear-stream _test-error-stream)
 5913     (clear-stream $_test-error-buffered-file->buffer)
 5914     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5915     68/push 0/imm32
 5916     68/push 0/imm32
 5917     89/<- %edx 4/r32/esp
 5918     (tailor-exit-descriptor %edx 0x10)
 5919     #
 5920     (write _test-input-stream "fn foo {\n")
 5921     (write _test-input-stream "  var a: int\n")
 5922     (write _test-input-stream "  add-to a, 0, 1\n")
 5923     (write _test-input-stream "}\n")
 5924     # convert
 5925     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5926     # registers except esp clobbered at this point
 5927     # restore ed
 5928     89/<- %edx 4/r32/esp
 5929     (flush _test-output-buffered-file)
 5930     (flush _test-error-buffered-file)
 5931 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5937     # check output
 5938     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-inouts-2: output should be empty")
 5939     (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")
 5940     # check that stop(1) was called
 5941     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-inouts-2: exit status")
 5942     # don't restore from ebp
 5943     81 0/subop/add %esp 8/imm32
 5944     # . epilogue
 5945     5d/pop-to-ebp
 5946     c3/return
 5947 
 5948 test-add-with-too-many-outputs:
 5949     # . prologue
 5950     55/push-ebp
 5951     89/<- %ebp 4/r32/esp
 5952     # setup
 5953     (clear-stream _test-input-stream)
 5954     (clear-stream $_test-input-buffered-file->buffer)
 5955     (clear-stream _test-output-stream)
 5956     (clear-stream $_test-output-buffered-file->buffer)
 5957     (clear-stream _test-error-stream)
 5958     (clear-stream $_test-error-buffered-file->buffer)
 5959     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5960     68/push 0/imm32
 5961     68/push 0/imm32
 5962     89/<- %edx 4/r32/esp
 5963     (tailor-exit-descriptor %edx 0x10)
 5964     #
 5965     (write _test-input-stream "fn foo {\n")
 5966     (write _test-input-stream "  var a/eax: int <- copy 0\n")
 5967     (write _test-input-stream "  var b/ebx: int <- copy 0\n")
 5968     (write _test-input-stream "  var c/ecx: int <- copy 0\n")
 5969     (write _test-input-stream "  c, b <- add a\n")
 5970     (write _test-input-stream "}\n")
 5971     # convert
 5972     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5973     # registers except esp clobbered at this point
 5974     # restore ed
 5975     89/<- %edx 4/r32/esp
 5976     (flush _test-output-buffered-file)
 5977     (flush _test-error-buffered-file)
 5978 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5984     # check output
 5985     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-outputs: output should be empty")
 5986     (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")
 5987     # check that stop(1) was called
 5988     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-outputs: exit status")
 5989     # don't restore from ebp
 5990     81 0/subop/add %esp 8/imm32
 5991     # . epilogue
 5992     5d/pop-to-ebp
 5993     c3/return
 5994 
 5995 test-add-with-non-number:
 5996     # . prologue
 5997     55/push-ebp
 5998     89/<- %ebp 4/r32/esp
 5999     # setup
 6000     (clear-stream _test-input-stream)
 6001     (clear-stream $_test-input-buffered-file->buffer)
 6002     (clear-stream _test-output-stream)
 6003     (clear-stream $_test-output-buffered-file->buffer)
 6004     (clear-stream _test-error-stream)
 6005     (clear-stream $_test-error-buffered-file->buffer)
 6006     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6007     68/push 0/imm32
 6008     68/push 0/imm32
 6009     89/<- %edx 4/r32/esp
 6010     (tailor-exit-descriptor %edx 0x10)
 6011     #
 6012     (write _test-input-stream "fn foo {\n")
 6013     (write _test-input-stream "  var a: int\n")
 6014     (write _test-input-stream "  var b/ecx: (addr int) <- add a\n")
 6015     (write _test-input-stream "}\n")
 6016     # convert
 6017     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6018     # registers except esp clobbered at this point
 6019     # restore ed
 6020     89/<- %edx 4/r32/esp
 6021     (flush _test-output-buffered-file)
 6022     (flush _test-error-buffered-file)
 6023 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6029     # check output
 6030     (check-stream-equal _test-output-stream  ""  "F - test-add-with-non-number: output should be empty")
 6031     (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")
 6032     # check that stop(1) was called
 6033     (check-ints-equal *(edx+4) 2 "F - test-add-with-non-number: exit status")
 6034     # don't restore from ebp
 6035     81 0/subop/add %esp 8/imm32
 6036     # . epilogue
 6037     5d/pop-to-ebp
 6038     c3/return
 6039 
 6040 test-add-with-addr-dereferenced:
 6041     # . prologue
 6042     55/push-ebp
 6043     89/<- %ebp 4/r32/esp
 6044     # setup
 6045     (clear-stream _test-input-stream)
 6046     (clear-stream $_test-input-buffered-file->buffer)
 6047     (clear-stream _test-output-stream)
 6048     (clear-stream $_test-output-buffered-file->buffer)
 6049     #
 6050     (write _test-input-stream "fn foo {\n")
 6051     (write _test-input-stream "  var a/eax: (addr int) <- copy 0\n")
 6052     (write _test-input-stream "  add-to *a, 1\n")
 6053     (write _test-input-stream "}\n")
 6054     # convert
 6055     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6056     (flush _test-output-buffered-file)
 6057     # no error
 6058     # . epilogue
 6059     89/<- %esp 5/r32/ebp
 6060     5d/pop-to-ebp
 6061     c3/return
 6062 
 6063 test-get-with-wrong-field:
 6064     # . prologue
 6065     55/push-ebp
 6066     89/<- %ebp 4/r32/esp
 6067     # setup
 6068     (clear-stream _test-input-stream)
 6069     (clear-stream $_test-input-buffered-file->buffer)
 6070     (clear-stream _test-output-stream)
 6071     (clear-stream $_test-output-buffered-file->buffer)
 6072     (clear-stream _test-error-stream)
 6073     (clear-stream $_test-error-buffered-file->buffer)
 6074     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6075     68/push 0/imm32
 6076     68/push 0/imm32
 6077     89/<- %edx 4/r32/esp
 6078     (tailor-exit-descriptor %edx 0x10)
 6079     #
 6080     (write _test-input-stream "fn foo {\n")
 6081     (write _test-input-stream "  var a: t\n")
 6082     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 6083     (write _test-input-stream "}\n")
 6084     (write _test-input-stream "type t {\n")
 6085     (write _test-input-stream "  x: int\n")
 6086     (write _test-input-stream "}\n")
 6087     # convert
 6088     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6089     # registers except esp clobbered at this point
 6090     # restore ed
 6091     89/<- %edx 4/r32/esp
 6092     (flush _test-output-buffered-file)
 6093     (flush _test-error-buffered-file)
 6094 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6100     # check output
 6101     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-field: output should be empty")
 6102     (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")
 6103     # check that stop(1) was called
 6104     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-field: exit status")
 6105     # don't restore from ebp
 6106     81 0/subop/add %esp 8/imm32
 6107     # . epilogue
 6108     5d/pop-to-ebp
 6109     c3/return
 6110 
 6111 test-get-with-wrong-base-type:
 6112     # . prologue
 6113     55/push-ebp
 6114     89/<- %ebp 4/r32/esp
 6115     # setup
 6116     (clear-stream _test-input-stream)
 6117     (clear-stream $_test-input-buffered-file->buffer)
 6118     (clear-stream _test-output-stream)
 6119     (clear-stream $_test-output-buffered-file->buffer)
 6120     (clear-stream _test-error-stream)
 6121     (clear-stream $_test-error-buffered-file->buffer)
 6122     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6123     68/push 0/imm32
 6124     68/push 0/imm32
 6125     89/<- %edx 4/r32/esp
 6126     (tailor-exit-descriptor %edx 0x10)
 6127     #
 6128     (write _test-input-stream "fn foo {\n")
 6129     (write _test-input-stream "  var a: int\n")
 6130     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 6131     (write _test-input-stream "}\n")
 6132     # convert
 6133     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6134     # registers except esp clobbered at this point
 6135     # restore ed
 6136     89/<- %edx 4/r32/esp
 6137     (flush _test-output-buffered-file)
 6138     (flush _test-error-buffered-file)
 6139 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6145     # check output
 6146     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-base-type: output should be empty")
 6147     (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")
 6148     # check that stop(1) was called
 6149     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-base-type: exit status")
 6150     # don't restore from ebp
 6151     81 0/subop/add %esp 8/imm32
 6152     # . epilogue
 6153     5d/pop-to-ebp
 6154     c3/return
 6155 
 6156 test-get-with-wrong-base-type-2:
 6157     # . prologue
 6158     55/push-ebp
 6159     89/<- %ebp 4/r32/esp
 6160     # setup
 6161     (clear-stream _test-input-stream)
 6162     (clear-stream $_test-input-buffered-file->buffer)
 6163     (clear-stream _test-output-stream)
 6164     (clear-stream $_test-output-buffered-file->buffer)
 6165     (clear-stream _test-error-stream)
 6166     (clear-stream $_test-error-buffered-file->buffer)
 6167     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6168     68/push 0/imm32
 6169     68/push 0/imm32
 6170     89/<- %edx 4/r32/esp
 6171     (tailor-exit-descriptor %edx 0x10)
 6172     #
 6173     (write _test-input-stream "fn foo {\n")
 6174     (write _test-input-stream "  var a: (addr t)\n")
 6175     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 6176     (write _test-input-stream "}\n")
 6177     (write _test-input-stream "type t {\n")
 6178     (write _test-input-stream "  x: int\n")
 6179     (write _test-input-stream "}\n")
 6180     # convert
 6181     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6182     # registers except esp clobbered at this point
 6183     # restore ed
 6184     89/<- %edx 4/r32/esp
 6185     (flush _test-output-buffered-file)
 6186     (flush _test-error-buffered-file)
 6187 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6193     # check output
 6194     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-base-type-2: output should be empty")
 6195     (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")
 6196     # check that stop(1) was called
 6197     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-base-type-2: exit status")
 6198     # don't restore from ebp
 6199     81 0/subop/add %esp 8/imm32
 6200     # . epilogue
 6201     5d/pop-to-ebp
 6202     c3/return
 6203 
 6204 test-get-with-wrong-offset-type:
 6205     # . prologue
 6206     55/push-ebp
 6207     89/<- %ebp 4/r32/esp
 6208     # setup
 6209     (clear-stream _test-input-stream)
 6210     (clear-stream $_test-input-buffered-file->buffer)
 6211     (clear-stream _test-output-stream)
 6212     (clear-stream $_test-output-buffered-file->buffer)
 6213     (clear-stream _test-error-stream)
 6214     (clear-stream $_test-error-buffered-file->buffer)
 6215     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6216     68/push 0/imm32
 6217     68/push 0/imm32
 6218     89/<- %edx 4/r32/esp
 6219     (tailor-exit-descriptor %edx 0x10)
 6220     #
 6221     (write _test-input-stream "fn foo {\n")
 6222     (write _test-input-stream "  var a: t\n")
 6223     (write _test-input-stream "  var b: int\n")
 6224     (write _test-input-stream "  var c/ecx: (addr int) <- get a, b\n")
 6225     (write _test-input-stream "}\n")
 6226     (write _test-input-stream "type t {\n")
 6227     (write _test-input-stream "  x: int\n")
 6228     (write _test-input-stream "}\n")
 6229     # convert
 6230     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6231     # registers except esp clobbered at this point
 6232     # restore ed
 6233     89/<- %edx 4/r32/esp
 6234     (flush _test-output-buffered-file)
 6235     (flush _test-error-buffered-file)
 6236 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6242     # check output
 6243     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-offset-type: output should be empty")
 6244     (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")
 6245     # check that stop(1) was called
 6246     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-offset-type: exit status")
 6247     # don't restore from ebp
 6248     81 0/subop/add %esp 8/imm32
 6249     # . epilogue
 6250     5d/pop-to-ebp
 6251     c3/return
 6252 
 6253 test-get-with-wrong-output-type:
 6254     # . prologue
 6255     55/push-ebp
 6256     89/<- %ebp 4/r32/esp
 6257     # setup
 6258     (clear-stream _test-input-stream)
 6259     (clear-stream $_test-input-buffered-file->buffer)
 6260     (clear-stream _test-output-stream)
 6261     (clear-stream $_test-output-buffered-file->buffer)
 6262     (clear-stream _test-error-stream)
 6263     (clear-stream $_test-error-buffered-file->buffer)
 6264     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6265     68/push 0/imm32
 6266     68/push 0/imm32
 6267     89/<- %edx 4/r32/esp
 6268     (tailor-exit-descriptor %edx 0x10)
 6269     #
 6270     (write _test-input-stream "fn foo {\n")
 6271     (write _test-input-stream "  var a: t\n")
 6272     (write _test-input-stream "  var c: (addr int)\n")
 6273     (write _test-input-stream "  c <- get a, x\n")
 6274     (write _test-input-stream "}\n")
 6275     (write _test-input-stream "type t {\n")
 6276     (write _test-input-stream "  x: int\n")
 6277     (write _test-input-stream "}\n")
 6278     # convert
 6279     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6280     # registers except esp clobbered at this point
 6281     # restore ed
 6282     89/<- %edx 4/r32/esp
 6283     (flush _test-output-buffered-file)
 6284     (flush _test-error-buffered-file)
 6285 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6291     # check output
 6292     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type: output should be empty")
 6293     (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")
 6294     # check that stop(1) was called
 6295     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type: exit status")
 6296     # don't restore from ebp
 6297     81 0/subop/add %esp 8/imm32
 6298     # . epilogue
 6299     5d/pop-to-ebp
 6300     c3/return
 6301 
 6302 test-get-with-wrong-output-type-2:
 6303     # . prologue
 6304     55/push-ebp
 6305     89/<- %ebp 4/r32/esp
 6306     # setup
 6307     (clear-stream _test-input-stream)
 6308     (clear-stream $_test-input-buffered-file->buffer)
 6309     (clear-stream _test-output-stream)
 6310     (clear-stream $_test-output-buffered-file->buffer)
 6311     (clear-stream _test-error-stream)
 6312     (clear-stream $_test-error-buffered-file->buffer)
 6313     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6314     68/push 0/imm32
 6315     68/push 0/imm32
 6316     89/<- %edx 4/r32/esp
 6317     (tailor-exit-descriptor %edx 0x10)
 6318     #
 6319     (write _test-input-stream "fn foo {\n")
 6320     (write _test-input-stream "  var a: t\n")
 6321     (write _test-input-stream "  var c/ecx: int <- get a, x\n")
 6322     (write _test-input-stream "}\n")
 6323     (write _test-input-stream "type t {\n")
 6324     (write _test-input-stream "  x: int\n")
 6325     (write _test-input-stream "}\n")
 6326     # convert
 6327     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6328     # registers except esp clobbered at this point
 6329     # restore ed
 6330     89/<- %edx 4/r32/esp
 6331     (flush _test-output-buffered-file)
 6332     (flush _test-error-buffered-file)
 6333 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6339     # check output
 6340     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-2: output should be empty")
 6341     (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")
 6342     # check that stop(1) was called
 6343     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-2: exit status")
 6344     # don't restore from ebp
 6345     81 0/subop/add %esp 8/imm32
 6346     # . epilogue
 6347     5d/pop-to-ebp
 6348     c3/return
 6349 
 6350 test-get-with-wrong-output-type-3:
 6351     # . prologue
 6352     55/push-ebp
 6353     89/<- %ebp 4/r32/esp
 6354     # setup
 6355     (clear-stream _test-input-stream)
 6356     (clear-stream $_test-input-buffered-file->buffer)
 6357     (clear-stream _test-output-stream)
 6358     (clear-stream $_test-output-buffered-file->buffer)
 6359     (clear-stream _test-error-stream)
 6360     (clear-stream $_test-error-buffered-file->buffer)
 6361     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6362     68/push 0/imm32
 6363     68/push 0/imm32
 6364     89/<- %edx 4/r32/esp
 6365     (tailor-exit-descriptor %edx 0x10)
 6366     #
 6367     (write _test-input-stream "fn foo {\n")
 6368     (write _test-input-stream "  var a: t\n")
 6369     (write _test-input-stream "  var c/ecx: (array int) <- get a, x\n")
 6370     (write _test-input-stream "}\n")
 6371     (write _test-input-stream "type t {\n")
 6372     (write _test-input-stream "  x: int\n")
 6373     (write _test-input-stream "}\n")
 6374     # convert
 6375     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6376     # registers except esp clobbered at this point
 6377     # restore ed
 6378     89/<- %edx 4/r32/esp
 6379     (flush _test-output-buffered-file)
 6380     (flush _test-error-buffered-file)
 6381 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6387     # check output
 6388     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-3: output should be empty")
 6389     (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")
 6390     # check that stop(1) was called
 6391     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-3: exit status")
 6392     # don't restore from ebp
 6393     81 0/subop/add %esp 8/imm32
 6394     # . epilogue
 6395     5d/pop-to-ebp
 6396     c3/return
 6397 
 6398 test-get-with-wrong-output-type-4:
 6399     # . prologue
 6400     55/push-ebp
 6401     89/<- %ebp 4/r32/esp
 6402     # setup
 6403     (clear-stream _test-input-stream)
 6404     (clear-stream $_test-input-buffered-file->buffer)
 6405     (clear-stream _test-output-stream)
 6406     (clear-stream $_test-output-buffered-file->buffer)
 6407     (clear-stream _test-error-stream)
 6408     (clear-stream $_test-error-buffered-file->buffer)
 6409     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6410     68/push 0/imm32
 6411     68/push 0/imm32
 6412     89/<- %edx 4/r32/esp
 6413     (tailor-exit-descriptor %edx 0x10)
 6414     #
 6415     (write _test-input-stream "fn foo {\n")
 6416     (write _test-input-stream "  var a: t\n")
 6417     (write _test-input-stream "  var c/ecx: (addr boolean) <- get a, x\n")
 6418     (write _test-input-stream "}\n")
 6419     (write _test-input-stream "type t {\n")
 6420     (write _test-input-stream "  x: int\n")
 6421     (write _test-input-stream "}\n")
 6422     # convert
 6423     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6424     # registers except esp clobbered at this point
 6425     # restore ed
 6426     89/<- %edx 4/r32/esp
 6427     (flush _test-output-buffered-file)
 6428     (flush _test-error-buffered-file)
 6429 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6435     # check output
 6436     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-4: output should be empty")
 6437     (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")
 6438     # check that stop(1) was called
 6439     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-4: exit status")
 6440     # don't restore from ebp
 6441     81 0/subop/add %esp 8/imm32
 6442     # . epilogue
 6443     5d/pop-to-ebp
 6444     c3/return
 6445 
 6446 test-get-with-wrong-output-type-5:
 6447     # . prologue
 6448     55/push-ebp
 6449     89/<- %ebp 4/r32/esp
 6450     # setup
 6451     (clear-stream _test-input-stream)
 6452     (clear-stream $_test-input-buffered-file->buffer)
 6453     (clear-stream _test-output-stream)
 6454     (clear-stream $_test-output-buffered-file->buffer)
 6455     #
 6456     (write _test-input-stream "fn foo {\n")
 6457     (write _test-input-stream "  var a: t\n")
 6458     (write _test-input-stream "  var c/ecx: (addr handle int) <- get a, x\n")
 6459     (write _test-input-stream "}\n")
 6460     (write _test-input-stream "type t {\n")
 6461     (write _test-input-stream "  x: (handle int)\n")
 6462     (write _test-input-stream "}\n")
 6463     # convert
 6464     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6465     (flush _test-output-buffered-file)
 6466     # no errors
 6467     # . epilogue
 6468     89/<- %esp 5/r32/ebp
 6469     5d/pop-to-ebp
 6470     c3/return
 6471 
 6472 test-get-with-too-few-inouts:
 6473     # . prologue
 6474     55/push-ebp
 6475     89/<- %ebp 4/r32/esp
 6476     # setup
 6477     (clear-stream _test-input-stream)
 6478     (clear-stream $_test-input-buffered-file->buffer)
 6479     (clear-stream _test-output-stream)
 6480     (clear-stream $_test-output-buffered-file->buffer)
 6481     (clear-stream _test-error-stream)
 6482     (clear-stream $_test-error-buffered-file->buffer)
 6483     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6484     68/push 0/imm32
 6485     68/push 0/imm32
 6486     89/<- %edx 4/r32/esp
 6487     (tailor-exit-descriptor %edx 0x10)
 6488     #
 6489     (write _test-input-stream "fn foo {\n")
 6490     (write _test-input-stream "  var a: t\n")
 6491     (write _test-input-stream "  var c/ecx: (addr int) <- get a\n")
 6492     (write _test-input-stream "}\n")
 6493     (write _test-input-stream "type t {\n")
 6494     (write _test-input-stream "  x: int\n")
 6495     (write _test-input-stream "}\n")
 6496     # convert
 6497     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6498     # registers except esp clobbered at this point
 6499     # restore ed
 6500     89/<- %edx 4/r32/esp
 6501     (flush _test-output-buffered-file)
 6502     (flush _test-error-buffered-file)
 6503 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6509     # check output
 6510     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-few-inouts: output should be empty")
 6511     (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")
 6512     # check that stop(1) was called
 6513     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-few-inouts: exit status")
 6514     # don't restore from ebp
 6515     81 0/subop/add %esp 8/imm32
 6516     # . epilogue
 6517     5d/pop-to-ebp
 6518     c3/return
 6519 
 6520 test-get-with-too-many-inouts:
 6521     # . prologue
 6522     55/push-ebp
 6523     89/<- %ebp 4/r32/esp
 6524     # setup
 6525     (clear-stream _test-input-stream)
 6526     (clear-stream $_test-input-buffered-file->buffer)
 6527     (clear-stream _test-output-stream)
 6528     (clear-stream $_test-output-buffered-file->buffer)
 6529     (clear-stream _test-error-stream)
 6530     (clear-stream $_test-error-buffered-file->buffer)
 6531     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6532     68/push 0/imm32
 6533     68/push 0/imm32
 6534     89/<- %edx 4/r32/esp
 6535     (tailor-exit-descriptor %edx 0x10)
 6536     #
 6537     (write _test-input-stream "fn foo {\n")
 6538     (write _test-input-stream "  var a: t\n")
 6539     (write _test-input-stream "  var c/ecx: (addr int) <- get a, x, 0\n")
 6540     (write _test-input-stream "}\n")
 6541     (write _test-input-stream "type t {\n")
 6542     (write _test-input-stream "  x: int\n")
 6543     (write _test-input-stream "}\n")
 6544     # convert
 6545     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6546     # registers except esp clobbered at this point
 6547     # restore ed
 6548     89/<- %edx 4/r32/esp
 6549     (flush _test-output-buffered-file)
 6550     (flush _test-error-buffered-file)
 6551 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6557     # check output
 6558     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-many-inouts: output should be empty")
 6559     (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")
 6560     # check that stop(1) was called
 6561     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-many-inouts: exit status")
 6562     # don't restore from ebp
 6563     81 0/subop/add %esp 8/imm32
 6564     # . epilogue
 6565     5d/pop-to-ebp
 6566     c3/return
 6567 
 6568 test-get-with-no-output:
 6569     # . prologue
 6570     55/push-ebp
 6571     89/<- %ebp 4/r32/esp
 6572     # setup
 6573     (clear-stream _test-input-stream)
 6574     (clear-stream $_test-input-buffered-file->buffer)
 6575     (clear-stream _test-output-stream)
 6576     (clear-stream $_test-output-buffered-file->buffer)
 6577     (clear-stream _test-error-stream)
 6578     (clear-stream $_test-error-buffered-file->buffer)
 6579     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6580     68/push 0/imm32
 6581     68/push 0/imm32
 6582     89/<- %edx 4/r32/esp
 6583     (tailor-exit-descriptor %edx 0x10)
 6584     #
 6585     (write _test-input-stream "fn foo {\n")
 6586     (write _test-input-stream "  var a: t\n")
 6587     (write _test-input-stream "  get a, x\n")
 6588     (write _test-input-stream "}\n")
 6589     (write _test-input-stream "type t {\n")
 6590     (write _test-input-stream "  x: int\n")
 6591     (write _test-input-stream "}\n")
 6592     # convert
 6593     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6594     # registers except esp clobbered at this point
 6595     # restore ed
 6596     89/<- %edx 4/r32/esp
 6597     (flush _test-output-buffered-file)
 6598     (flush _test-error-buffered-file)
 6599 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6605     # check output
 6606     (check-stream-equal _test-output-stream  ""  "F - test-get-with-no-output: output should be empty")
 6607     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: must have an output"  "F - test-get-with-no-output: error message")
 6608     # check that stop(1) was called
 6609     (check-ints-equal *(edx+4) 2 "F - test-get-with-no-output: exit status")
 6610     # don't restore from ebp
 6611     81 0/subop/add %esp 8/imm32
 6612     # . epilogue
 6613     5d/pop-to-ebp
 6614     c3/return
 6615 
 6616 test-get-with-too-many-outputs:
 6617     # . prologue
 6618     55/push-ebp
 6619     89/<- %ebp 4/r32/esp
 6620     # setup
 6621     (clear-stream _test-input-stream)
 6622     (clear-stream $_test-input-buffered-file->buffer)
 6623     (clear-stream _test-output-stream)
 6624     (clear-stream $_test-output-buffered-file->buffer)
 6625     (clear-stream _test-error-stream)
 6626     (clear-stream $_test-error-buffered-file->buffer)
 6627     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6628     68/push 0/imm32
 6629     68/push 0/imm32
 6630     89/<- %edx 4/r32/esp
 6631     (tailor-exit-descriptor %edx 0x10)
 6632     #
 6633     (write _test-input-stream "fn foo {\n")
 6634     (write _test-input-stream "  var a: t\n")
 6635     (write _test-input-stream "  var b: int\n")
 6636     (write _test-input-stream "  var c/eax: (addr int) <- copy 0\n")
 6637     (write _test-input-stream "  c, b <- get a, x\n")
 6638     (write _test-input-stream "}\n")
 6639     (write _test-input-stream "type t {\n")
 6640     (write _test-input-stream "  x: int\n")
 6641     (write _test-input-stream "}\n")
 6642     # convert
 6643     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6644     # registers except esp clobbered at this point
 6645     # restore ed
 6646     89/<- %edx 4/r32/esp
 6647     (flush _test-output-buffered-file)
 6648     (flush _test-error-buffered-file)
 6649 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6655     # check output
 6656     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-many-outputs: output should be empty")
 6657     (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")
 6658     # check that stop(1) was called
 6659     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-many-outputs: exit status")
 6660     # don't restore from ebp
 6661     81 0/subop/add %esp 8/imm32
 6662     # . epilogue
 6663     5d/pop-to-ebp
 6664     c3/return
 6665 
 6666 test-convert-array-of-user-defined-types:
 6667     # . prologue
 6668     55/push-ebp
 6669     89/<- %ebp 4/r32/esp
 6670     # setup
 6671     (clear-stream _test-input-stream)
 6672     (clear-stream $_test-input-buffered-file->buffer)
 6673     (clear-stream _test-output-stream)
 6674     (clear-stream $_test-output-buffered-file->buffer)
 6675     #
 6676     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
 6677     (write _test-input-stream "  x: int\n")
 6678     (write _test-input-stream "  y: int\n")
 6679     (write _test-input-stream "}\n")
 6680     (write _test-input-stream "fn foo {\n")
 6681     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6682     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 6683     (write _test-input-stream "  var x/eax: (addr t) <- index arr, idx\n")
 6684     (write _test-input-stream "}\n")
 6685     # convert
 6686     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6687     (flush _test-output-buffered-file)
 6688 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6694     # check output
 6695     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-array-of-user-defined-types/0")
 6696     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-array-of-user-defined-types/1")
 6697     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-array-of-user-defined-types/2")
 6698     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-array-of-user-defined-types/3")
 6699     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-array-of-user-defined-types/4")
 6700     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-array-of-user-defined-types/5")
 6701     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-array-of-user-defined-types/6")
 6702     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-array-of-user-defined-types/7")
 6703     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-array-of-user-defined-types/8")
 6704     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-array-of-user-defined-types/9")
 6705     (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")
 6706     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-array-of-user-defined-types/13")
 6707     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-array-of-user-defined-types/14")
 6708     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-array-of-user-defined-types/15")
 6709     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-array-of-user-defined-types/16")
 6710     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-array-of-user-defined-types/17")
 6711     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-array-of-user-defined-types/18")
 6712     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-array-of-user-defined-types/19")
 6713     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-array-of-user-defined-types/20")
 6714     # . epilogue
 6715     89/<- %esp 5/r32/ebp
 6716     5d/pop-to-ebp
 6717     c3/return
 6718 
 6719 test-convert-length-of-array-of-user-defined-types-to-eax:
 6720     # . prologue
 6721     55/push-ebp
 6722     89/<- %ebp 4/r32/esp
 6723     # setup
 6724     (clear-stream _test-input-stream)
 6725     (clear-stream $_test-input-buffered-file->buffer)
 6726     (clear-stream _test-output-stream)
 6727     (clear-stream $_test-output-buffered-file->buffer)
 6728     #
 6729     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 6730     (write _test-input-stream "  x: int\n")
 6731     (write _test-input-stream "  y: int\n")
 6732     (write _test-input-stream "  z: int\n")
 6733     (write _test-input-stream "}\n")
 6734     (write _test-input-stream "fn foo {\n")
 6735     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6736     (write _test-input-stream "  var x/eax: (addr t) <- length arr\n")
 6737     (write _test-input-stream "}\n")
 6738     # convert
 6739     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6740     (flush _test-output-buffered-file)
 6741 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6747     # check output
 6748     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-eax/0")
 6749     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/1")
 6750     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-eax/2")
 6751     (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")
 6752     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/4")
 6753     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-eax/5")
 6754     # var arr
 6755     (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")
 6756     (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")
 6757     # length instruction
 6758     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/8")
 6759     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/9")
 6760     (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")
 6761     (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")
 6762     (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")
 6763     (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")
 6764     (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")
 6765     (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")
 6766     # reclaim arr
 6767     (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")
 6768     #
 6769     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/17")
 6770     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/18")
 6771     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/19")
 6772     (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")
 6773     (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")
 6774     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-eax/22")
 6775     # . epilogue
 6776     89/<- %esp 5/r32/ebp
 6777     5d/pop-to-ebp
 6778     c3/return
 6779 
 6780 test-convert-length-of-array-of-user-defined-types-to-ecx:
 6781     # . prologue
 6782     55/push-ebp
 6783     89/<- %ebp 4/r32/esp
 6784     # setup
 6785     (clear-stream _test-input-stream)
 6786     (clear-stream $_test-input-buffered-file->buffer)
 6787     (clear-stream _test-output-stream)
 6788     (clear-stream $_test-output-buffered-file->buffer)
 6789     #
 6790     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 6791     (write _test-input-stream "  x: int\n")
 6792     (write _test-input-stream "  y: int\n")
 6793     (write _test-input-stream "  z: int\n")
 6794     (write _test-input-stream "}\n")
 6795     (write _test-input-stream "fn foo {\n")
 6796     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6797     (write _test-input-stream "  var x/ecx: (addr t) <- length arr\n")
 6798     (write _test-input-stream "}\n")
 6799     # convert
 6800     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6801     (flush _test-output-buffered-file)
 6802 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6808     # check output
 6809     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-ecx/0")
 6810     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/1")
 6811     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-ecx/2")
 6812     (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")
 6813     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/4")
 6814     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-ecx/5")
 6815     # var a
 6816     (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")
 6817     (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")
 6818     # var x
 6819     (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")
 6820     # length instruction
 6821     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/9")
 6822     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/10")
 6823     (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")
 6824     (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")
 6825     (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")
 6826     (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")
 6827     (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")
 6828     (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")
 6829     (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")
 6830     # reclaim x
 6831     (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")
 6832     # reclaim a
 6833     (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")
 6834     #
 6835     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/20")
 6836     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/21")
 6837     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/22")
 6838     (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")
 6839     (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")
 6840     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-ecx/25")
 6841     # . epilogue
 6842     89/<- %esp 5/r32/ebp
 6843     5d/pop-to-ebp
 6844     c3/return
 6845 
 6846 test-convert-length-of-array-of-user-defined-types-to-edx:
 6847     # . prologue
 6848     55/push-ebp
 6849     89/<- %ebp 4/r32/esp
 6850     # setup
 6851     (clear-stream _test-input-stream)
 6852     (clear-stream $_test-input-buffered-file->buffer)
 6853     (clear-stream _test-output-stream)
 6854     (clear-stream $_test-output-buffered-file->buffer)
 6855     #
 6856     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 6857     (write _test-input-stream "  x: int\n")
 6858     (write _test-input-stream "  y: int\n")
 6859     (write _test-input-stream "  z: int\n")
 6860     (write _test-input-stream "}\n")
 6861     (write _test-input-stream "fn foo {\n")
 6862     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6863     (write _test-input-stream "  var x/edx: (addr t) <- length arr\n")
 6864     (write _test-input-stream "}\n")
 6865     # convert
 6866     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6867     (flush _test-output-buffered-file)
 6868 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6874     # check output
 6875     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-edx/0")
 6876     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/1")
 6877     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-edx/2")
 6878     (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")
 6879     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/4")
 6880     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-edx/5")
 6881     # var a
 6882     (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")
 6883     (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")
 6884     # var x
 6885     (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")
 6886     # length instruction
 6887     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/9")
 6888     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/10")
 6889     (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")
 6890     (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")
 6891     (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")
 6892     (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")
 6893     (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")
 6894     (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")
 6895     (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")
 6896     # reclaim x
 6897     (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")
 6898     # reclaim a
 6899     (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")
 6900     #
 6901     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/20")
 6902     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/21")
 6903     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/22")
 6904     (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")
 6905     (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")
 6906     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-edx/25")
 6907     # . epilogue
 6908     89/<- %esp 5/r32/ebp
 6909     5d/pop-to-ebp
 6910     c3/return
 6911 
 6912 test-convert-length-of-array-of-user-defined-types:
 6913     # . prologue
 6914     55/push-ebp
 6915     89/<- %ebp 4/r32/esp
 6916     # setup
 6917     (clear-stream _test-input-stream)
 6918     (clear-stream $_test-input-buffered-file->buffer)
 6919     (clear-stream _test-output-stream)
 6920     (clear-stream $_test-output-buffered-file->buffer)
 6921     #
 6922     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
 6923     (write _test-input-stream "  x: int\n")
 6924     (write _test-input-stream "  y: int\n")
 6925     (write _test-input-stream "  z: int\n")
 6926     (write _test-input-stream "}\n")
 6927     (write _test-input-stream "fn foo {\n")
 6928     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6929     (write _test-input-stream "  var x/ebx: (addr t) <- length arr\n")
 6930     (write _test-input-stream "}\n")
 6931     # convert
 6932     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6933     (flush _test-output-buffered-file)
 6934 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6940     # check output
 6941     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types/0")
 6942     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types/1")
 6943     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types/2")
 6944     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-user-defined-types/3")
 6945     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types/4")
 6946     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types/5")
 6947     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-user-defined-types/6")
 6948     (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")
 6949     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ebx"  "F - test-convert-length-of-array-of-user-defined-types/8")
 6950     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types/9")
 6951     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types/10")
 6952     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types/11")
 6953     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-user-defined-types/12")
 6954     (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")
 6955     (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")
 6956     (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")
 6957     (check-next-stream-line-equal _test-output-stream "    89/<- %ebx 0/r32/eax"  "F - test-convert-length-of-array-of-user-defined-types/16")
 6958     (check-next-stream-line-equal _test-output-stream "    5a/pop-to-edx"       "F - test-convert-length-of-array-of-user-defined-types/17")
 6959     (check-next-stream-line-equal _test-output-stream "    59/pop-to-ecx"       "F - test-convert-length-of-array-of-user-defined-types/18")
 6960     (check-next-stream-line-equal _test-output-stream "    58/pop-to-eax"       "F - test-convert-length-of-array-of-user-defined-types/19")
 6961     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ebx"  "F - test-convert-length-of-array-of-user-defined-types/20")
 6962     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-user-defined-types/21")
 6963     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types/22")
 6964     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types/23")
 6965     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types/24")
 6966     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-user-defined-types/25")
 6967     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-user-defined-types/26")
 6968     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types/27")
 6969     # . epilogue
 6970     89/<- %esp 5/r32/ebp
 6971     5d/pop-to-ebp
 6972     c3/return
 6973 
 6974 test-index-with-non-array-atom-base-type:
 6975     # . prologue
 6976     55/push-ebp
 6977     89/<- %ebp 4/r32/esp
 6978     # setup
 6979     (clear-stream _test-input-stream)
 6980     (clear-stream $_test-input-buffered-file->buffer)
 6981     (clear-stream _test-output-stream)
 6982     (clear-stream $_test-output-buffered-file->buffer)
 6983     (clear-stream _test-error-stream)
 6984     (clear-stream $_test-error-buffered-file->buffer)
 6985     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6986     68/push 0/imm32
 6987     68/push 0/imm32
 6988     89/<- %edx 4/r32/esp
 6989     (tailor-exit-descriptor %edx 0x10)
 6990     #
 6991     (write _test-input-stream "fn foo {\n")
 6992     (write _test-input-stream "  var a: int\n")
 6993     (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
 6994     (write _test-input-stream "}\n")
 6995     # convert
 6996     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6997     # registers except esp clobbered at this point
 6998     # restore ed
 6999     89/<- %edx 4/r32/esp
 7000     (flush _test-output-buffered-file)
 7001     (flush _test-error-buffered-file)
 7002 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7008     # check output
 7009     (check-stream-equal _test-output-stream  ""  "F - test-index-with-non-array-atom-base-type: output should be empty")
 7010     (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")
 7011     # check that stop(1) was called
 7012     (check-ints-equal *(edx+4) 2 "F - test-index-with-non-array-atom-base-type: exit status")
 7013     # don't restore from ebp
 7014     81 0/subop/add %esp 8/imm32
 7015     # . epilogue
 7016     5d/pop-to-ebp
 7017     c3/return
 7018 
 7019 test-index-with-non-array-compound-base-type:
 7020     # . prologue
 7021     55/push-ebp
 7022     89/<- %ebp 4/r32/esp
 7023     # setup
 7024     (clear-stream _test-input-stream)
 7025     (clear-stream $_test-input-buffered-file->buffer)
 7026     (clear-stream _test-output-stream)
 7027     (clear-stream $_test-output-buffered-file->buffer)
 7028     (clear-stream _test-error-stream)
 7029     (clear-stream $_test-error-buffered-file->buffer)
 7030     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7031     68/push 0/imm32
 7032     68/push 0/imm32
 7033     89/<- %edx 4/r32/esp
 7034     (tailor-exit-descriptor %edx 0x10)
 7035     #
 7036     (write _test-input-stream "fn foo {\n")
 7037     (write _test-input-stream "  var a: (handle int)\n")
 7038     (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
 7039     (write _test-input-stream "}\n")
 7040     # convert
 7041     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7042     # registers except esp clobbered at this point
 7043     # restore ed
 7044     89/<- %edx 4/r32/esp
 7045     (flush _test-output-buffered-file)
 7046     (flush _test-error-buffered-file)
 7047 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7053     # check output
 7054     (check-stream-equal _test-output-stream  ""  "F - test-index-with-non-array-compound-base-type: output should be empty")
 7055     (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")
 7056     # check that stop(1) was called
 7057     (check-ints-equal *(edx+4) 2 "F - test-index-with-non-array-compound-base-type: exit status")
 7058     # don't restore from ebp
 7059     81 0/subop/add %esp 8/imm32
 7060     # . epilogue
 7061     5d/pop-to-ebp
 7062     c3/return
 7063 
 7064 test-index-with-non-array-compound-base-type-2:
 7065     # . prologue
 7066     55/push-ebp
 7067     89/<- %ebp 4/r32/esp
 7068     # setup
 7069     (clear-stream _test-input-stream)
 7070     (clear-stream $_test-input-buffered-file->buffer)
 7071     (clear-stream _test-output-stream)
 7072     (clear-stream $_test-output-buffered-file->buffer)
 7073     (clear-stream _test-error-stream)
 7074     (clear-stream $_test-error-buffered-file->buffer)
 7075     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7076     68/push 0/imm32
 7077     68/push 0/imm32
 7078     89/<- %edx 4/r32/esp
 7079     (tailor-exit-descriptor %edx 0x10)
 7080     #
 7081     (write _test-input-stream "fn foo {\n")
 7082     (write _test-input-stream "  var a: (addr int)\n")
 7083     (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
 7084     (write _test-input-stream "}\n")
 7085     # convert
 7086     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7087     # registers except esp clobbered at this point
 7088     # restore ed
 7089     89/<- %edx 4/r32/esp
 7090     (flush _test-output-buffered-file)
 7091     (flush _test-error-buffered-file)
 7092 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7098     # check output
 7099     (check-stream-equal _test-output-stream  ""  "F - test-index-with-non-array-compound-base-type-2: output should be empty")
 7100     (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")
 7101     # check that stop(1) was called
 7102     (check-ints-equal *(edx+4) 2 "F - test-index-with-non-array-compound-base-type-2: exit status")
 7103     # don't restore from ebp
 7104     81 0/subop/add %esp 8/imm32
 7105     # . epilogue
 7106     5d/pop-to-ebp
 7107     c3/return
 7108 
 7109 test-index-with-array-atom-base-type:
 7110     # . prologue
 7111     55/push-ebp
 7112     89/<- %ebp 4/r32/esp
 7113     # setup
 7114     (clear-stream _test-input-stream)
 7115     (clear-stream $_test-input-buffered-file->buffer)
 7116     (clear-stream _test-output-stream)
 7117     (clear-stream $_test-output-buffered-file->buffer)
 7118     (clear-stream _test-error-stream)
 7119     (clear-stream $_test-error-buffered-file->buffer)
 7120     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7121     68/push 0/imm32
 7122     68/push 0/imm32
 7123     89/<- %edx 4/r32/esp
 7124     (tailor-exit-descriptor %edx 0x10)
 7125     #
 7126     (write _test-input-stream "fn foo {\n")
 7127     (write _test-input-stream "  var a: array\n")
 7128     (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
 7129     (write _test-input-stream "}\n")
 7130     # convert
 7131     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7132     # registers except esp clobbered at this point
 7133     # restore ed
 7134     89/<- %edx 4/r32/esp
 7135     (flush _test-output-buffered-file)
 7136     (flush _test-error-buffered-file)
 7137 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7143     # check output
 7144     (check-stream-equal _test-output-stream  ""  "F - test-index-with-array-atom-base-type: output should be empty")
 7145     (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")
 7146     # check that stop(1) was called
 7147     (check-ints-equal *(edx+4) 2 "F - test-index-with-array-atom-base-type: exit status")
 7148     # don't restore from ebp
 7149     81 0/subop/add %esp 8/imm32
 7150     # . epilogue
 7151     5d/pop-to-ebp
 7152     c3/return
 7153 
 7154 test-index-with-addr-base-on-stack:
 7155     # . prologue
 7156     55/push-ebp
 7157     89/<- %ebp 4/r32/esp
 7158     # setup
 7159     (clear-stream _test-input-stream)
 7160     (clear-stream $_test-input-buffered-file->buffer)
 7161     (clear-stream _test-output-stream)
 7162     (clear-stream $_test-output-buffered-file->buffer)
 7163     (clear-stream _test-error-stream)
 7164     (clear-stream $_test-error-buffered-file->buffer)
 7165     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7166     68/push 0/imm32
 7167     68/push 0/imm32
 7168     89/<- %edx 4/r32/esp
 7169     (tailor-exit-descriptor %edx 0x10)
 7170     #
 7171     (write _test-input-stream "fn foo {\n")
 7172     (write _test-input-stream "  var a: (addr array int)\n")
 7173     (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
 7174     (write _test-input-stream "}\n")
 7175     # convert
 7176     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7177     # registers except esp clobbered at this point
 7178     # restore ed
 7179     89/<- %edx 4/r32/esp
 7180     (flush _test-output-buffered-file)
 7181     (flush _test-error-buffered-file)
 7182 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7188     # check output
 7189     (check-stream-equal _test-output-stream  ""  "F - test-index-with-addr-base-on-stack: output should be empty")
 7190     (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")
 7191     # check that stop(1) was called
 7192     (check-ints-equal *(edx+4) 2 "F - test-index-with-addr-base-on-stack: exit status")
 7193     # don't restore from ebp
 7194     81 0/subop/add %esp 8/imm32
 7195     # . epilogue
 7196     5d/pop-to-ebp
 7197     c3/return
 7198 
 7199 test-index-with-array-base-in-register:
 7200     # . prologue
 7201     55/push-ebp
 7202     89/<- %ebp 4/r32/esp
 7203     # setup
 7204     (clear-stream _test-input-stream)
 7205     (clear-stream $_test-input-buffered-file->buffer)
 7206     (clear-stream _test-output-stream)
 7207     (clear-stream $_test-output-buffered-file->buffer)
 7208     (clear-stream _test-error-stream)
 7209     (clear-stream $_test-error-buffered-file->buffer)
 7210     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7211     68/push 0/imm32
 7212     68/push 0/imm32
 7213     89/<- %edx 4/r32/esp
 7214     (tailor-exit-descriptor %edx 0x10)
 7215     #
 7216     (write _test-input-stream "fn foo {\n")
 7217     (write _test-input-stream "  var a/eax: (array int 3) <- copy 0\n")
 7218     (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
 7219     (write _test-input-stream "}\n")
 7220     # convert
 7221     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7222     # registers except esp clobbered at this point
 7223     # restore ed
 7224     89/<- %edx 4/r32/esp
 7225     (flush _test-output-buffered-file)
 7226     (flush _test-error-buffered-file)
 7227 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7233     # check output
 7234     (check-stream-equal _test-output-stream  ""  "F - test-index-with-array-base-in-register: output should be empty")
 7235     (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")
 7236     # check that stop(1) was called
 7237     (check-ints-equal *(edx+4) 2 "F - test-index-with-array-base-in-register: exit status")
 7238     # don't restore from ebp
 7239     81 0/subop/add %esp 8/imm32
 7240     # . epilogue
 7241     5d/pop-to-ebp
 7242     c3/return
 7243 
 7244 test-index-with-wrong-index-type:
 7245     # . prologue
 7246     55/push-ebp
 7247     89/<- %ebp 4/r32/esp
 7248     # setup
 7249     (clear-stream _test-input-stream)
 7250     (clear-stream $_test-input-buffered-file->buffer)
 7251     (clear-stream _test-output-stream)
 7252     (clear-stream $_test-output-buffered-file->buffer)
 7253     (clear-stream _test-error-stream)
 7254     (clear-stream $_test-error-buffered-file->buffer)
 7255     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7256     68/push 0/imm32
 7257     68/push 0/imm32
 7258     89/<- %edx 4/r32/esp
 7259     (tailor-exit-descriptor %edx 0x10)
 7260     #
 7261     (write _test-input-stream "fn foo {\n")
 7262     (write _test-input-stream "  var a/eax: (addr array int) <- copy 0\n")
 7263     (write _test-input-stream "  var b: boolean\n")
 7264     (write _test-input-stream "  var c/ecx: (addr int) <- index a, b\n")
 7265     (write _test-input-stream "}\n")
 7266     # convert
 7267     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7268     # registers except esp clobbered at this point
 7269     # restore ed
 7270     89/<- %edx 4/r32/esp
 7271     (flush _test-output-buffered-file)
 7272     (flush _test-error-buffered-file)
 7273 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7279     # check output
 7280     (check-stream-equal _test-output-stream  ""  "F - test-index-with-wrong-index-type: output should be empty")
 7281     (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")
 7282     # check that stop(1) was called
 7283     (check-ints-equal *(edx+4) 2 "F - test-index-with-wrong-index-type: exit status")
 7284     # don't restore from ebp
 7285     81 0/subop/add %esp 8/imm32
 7286     # . epilogue
 7287     5d/pop-to-ebp
 7288     c3/return
 7289 
 7290 test-index-with-offset-atom-index-type:
 7291     # . prologue
 7292     55/push-ebp
 7293     89/<- %ebp 4/r32/esp
 7294     # setup
 7295     (clear-stream _test-input-stream)
 7296     (clear-stream $_test-input-buffered-file->buffer)
 7297     (clear-stream _test-output-stream)
 7298     (clear-stream $_test-output-buffered-file->buffer)
 7299     (clear-stream _test-error-stream)
 7300     (clear-stream $_test-error-buffered-file->buffer)
 7301     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7302     68/push 0/imm32
 7303     68/push 0/imm32
 7304     89/<- %edx 4/r32/esp
 7305     (tailor-exit-descriptor %edx 0x10)
 7306     #
 7307     (write _test-input-stream "fn foo {\n")
 7308     (write _test-input-stream "  var a/eax: (addr array int) <- copy 0\n")
 7309     (write _test-input-stream "  var b: offset\n")
 7310     (write _test-input-stream "  var c/ecx: (addr int) <- index a, b\n")
 7311     (write _test-input-stream "}\n")
 7312     # convert
 7313     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7314     # registers except esp clobbered at this point
 7315     # restore ed
 7316     89/<- %edx 4/r32/esp
 7317     (flush _test-output-buffered-file)
 7318     (flush _test-error-buffered-file)
 7319 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7325     # check output
 7326     (check-stream-equal _test-output-stream  ""  "F - test-index-with-offset-atom-index-type: output should be empty")
 7327     (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")
 7328     # check that stop(1) was called
 7329     (check-ints-equal *(edx+4) 2 "F - test-index-with-offset-atom-index-type: exit status")
 7330     # don't restore from ebp
 7331     81 0/subop/add %esp 8/imm32
 7332     # . epilogue
 7333     5d/pop-to-ebp
 7334     c3/return
 7335 
 7336 test-index-with-offset-on-stack:
 7337     # . prologue
 7338     55/push-ebp
 7339     89/<- %ebp 4/r32/esp
 7340     # setup
 7341     (clear-stream _test-input-stream)
 7342     (clear-stream $_test-input-buffered-file->buffer)
 7343     (clear-stream _test-output-stream)
 7344     (clear-stream $_test-output-buffered-file->buffer)
 7345     (clear-stream _test-error-stream)
 7346     (clear-stream $_test-error-buffered-file->buffer)
 7347     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7348     68/push 0/imm32
 7349     68/push 0/imm32
 7350     89/<- %edx 4/r32/esp
 7351     (tailor-exit-descriptor %edx 0x10)
 7352     #
 7353     (write _test-input-stream "fn foo {\n")
 7354     (write _test-input-stream "  var a/eax: (addr array int) <- copy 0\n")
 7355     (write _test-input-stream "  var b: int\n")
 7356     (write _test-input-stream "  var c/ecx: (addr int) <- index a, b\n")
 7357     (write _test-input-stream "}\n")
 7358     # convert
 7359     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7360     # registers except esp clobbered at this point
 7361     # restore ed
 7362     89/<- %edx 4/r32/esp
 7363     (flush _test-output-buffered-file)
 7364     (flush _test-error-buffered-file)
 7365 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7371     # check output
 7372     (check-stream-equal _test-output-stream  ""  "F - test-index-with-offset-on-stack: output should be empty")
 7373     (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")
 7374     # check that stop(1) was called
 7375     (check-ints-equal *(edx+4) 2 "F - test-index-with-offset-on-stack: exit status")
 7376     # don't restore from ebp
 7377     81 0/subop/add %esp 8/imm32
 7378     # . epilogue
 7379     5d/pop-to-ebp
 7380     c3/return
 7381 
 7382 test-index-needs-offset-type:
 7383     # . prologue
 7384     55/push-ebp
 7385     89/<- %ebp 4/r32/esp
 7386     # setup
 7387     (clear-stream _test-input-stream)
 7388     (clear-stream $_test-input-buffered-file->buffer)
 7389     (clear-stream _test-output-stream)
 7390     (clear-stream $_test-output-buffered-file->buffer)
 7391     (clear-stream _test-error-stream)
 7392     (clear-stream $_test-error-buffered-file->buffer)
 7393     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7394     68/push 0/imm32
 7395     68/push 0/imm32
 7396     89/<- %edx 4/r32/esp
 7397     (tailor-exit-descriptor %edx 0x10)
 7398     #
 7399     (write _test-input-stream "fn foo {\n")
 7400     (write _test-input-stream "  var a/eax: (addr array t) <- copy 0\n")
 7401     (write _test-input-stream "  var b/ebx: int <- copy 0\n")
 7402     (write _test-input-stream "  var c/ecx: (addr int) <- index a, b\n")
 7403     (write _test-input-stream "}\n")
 7404     (write _test-input-stream "type t {\n")  # size 12 is not a power of two
 7405     (write _test-input-stream "  x: int\n")
 7406     (write _test-input-stream "  y: int\n")
 7407     (write _test-input-stream "  z: int\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-needs-offset-type: output should be empty")
 7424     (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")
 7425     # check that stop(1) was called
 7426     (check-ints-equal *(edx+4) 2 "F - test-index-needs-offset-type: 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-output-not-address:
 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/ebx: (addr array boolean) <- copy 0\n")
 7452     (write _test-input-stream "  var o/edi: int <- index a, 0\n")
 7453     (write _test-input-stream "}\n")
 7454     # convert
 7455     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7456     # registers except esp clobbered at this point
 7457     # restore ed
 7458     89/<- %edx 4/r32/esp
 7459     (flush _test-output-buffered-file)
 7460     (flush _test-error-buffered-file)
 7461 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7467     # check output
 7468     (check-stream-equal _test-output-stream  ""  "F - test-index-with-output-not-address: output should be empty")
 7469     (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")
 7470     # check that stop(1) was called
 7471     (check-ints-equal *(edx+4) 2 "F - test-index-with-output-not-address: exit status")
 7472     # don't restore from ebp
 7473     81 0/subop/add %esp 8/imm32
 7474     # . epilogue
 7475     5d/pop-to-ebp
 7476     c3/return
 7477 
 7478 test-index-with-output-not-address-2:
 7479     # . prologue
 7480     55/push-ebp
 7481     89/<- %ebp 4/r32/esp
 7482     # setup
 7483     (clear-stream _test-input-stream)
 7484     (clear-stream $_test-input-buffered-file->buffer)
 7485     (clear-stream _test-output-stream)
 7486     (clear-stream $_test-output-buffered-file->buffer)
 7487     (clear-stream _test-error-stream)
 7488     (clear-stream $_test-error-buffered-file->buffer)
 7489     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7490     68/push 0/imm32
 7491     68/push 0/imm32
 7492     89/<- %edx 4/r32/esp
 7493     (tailor-exit-descriptor %edx 0x10)
 7494     #
 7495     (write _test-input-stream "fn foo {\n")
 7496     (write _test-input-stream "  var a/ebx: (addr array boolean) <- copy 0\n")
 7497     (write _test-input-stream "  var o/edi: (int) <- index a, 0\n")
 7498     (write _test-input-stream "}\n")
 7499     # convert
 7500     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7501     # registers except esp clobbered at this point
 7502     # restore ed
 7503     89/<- %edx 4/r32/esp
 7504     (flush _test-output-buffered-file)
 7505     (flush _test-error-buffered-file)
 7506 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7512     # check output
 7513     (check-stream-equal _test-output-stream  ""  "F - test-index-with-output-not-address-2: output should be empty")
 7514     (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")
 7515     # check that stop(1) was called
 7516     (check-ints-equal *(edx+4) 2 "F - test-index-with-output-not-address-2: exit status")
 7517     # don't restore from ebp
 7518     81 0/subop/add %esp 8/imm32
 7519     # . epilogue
 7520     5d/pop-to-ebp
 7521     c3/return
 7522 
 7523 test-index-with-wrong-output-type:
 7524     # . prologue
 7525     55/push-ebp
 7526     89/<- %ebp 4/r32/esp
 7527     # setup
 7528     (clear-stream _test-input-stream)
 7529     (clear-stream $_test-input-buffered-file->buffer)
 7530     (clear-stream _test-output-stream)
 7531     (clear-stream $_test-output-buffered-file->buffer)
 7532     (clear-stream _test-error-stream)
 7533     (clear-stream $_test-error-buffered-file->buffer)
 7534     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7535     68/push 0/imm32
 7536     68/push 0/imm32
 7537     89/<- %edx 4/r32/esp
 7538     (tailor-exit-descriptor %edx 0x10)
 7539     #
 7540     (write _test-input-stream "fn foo {\n")
 7541     (write _test-input-stream "  var a/ebx: (addr array boolean) <- copy 0\n")
 7542     (write _test-input-stream "  var o/edi: (addr int) <- index a, 0\n")
 7543     (write _test-input-stream "}\n")
 7544     # convert
 7545     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7546     # registers except esp clobbered at this point
 7547     # restore ed
 7548     89/<- %edx 4/r32/esp
 7549     (flush _test-output-buffered-file)
 7550     (flush _test-error-buffered-file)
 7551 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7557     # check output
 7558     (check-stream-equal _test-output-stream  ""  "F - test-index-with-wrong-output-type: output should be empty")
 7559     (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")
 7560     # check that stop(1) was called
 7561     (check-ints-equal *(edx+4) 2 "F - test-index-with-wrong-output-type: exit status")
 7562     # don't restore from ebp
 7563     81 0/subop/add %esp 8/imm32
 7564     # . epilogue
 7565     5d/pop-to-ebp
 7566     c3/return
 7567 
 7568 test-index-with-wrong-output-compound-type:
 7569     # . prologue
 7570     55/push-ebp
 7571     89/<- %ebp 4/r32/esp
 7572     # setup
 7573     (clear-stream _test-input-stream)
 7574     (clear-stream $_test-input-buffered-file->buffer)
 7575     (clear-stream _test-output-stream)
 7576     (clear-stream $_test-output-buffered-file->buffer)
 7577     (clear-stream _test-error-stream)
 7578     (clear-stream $_test-error-buffered-file->buffer)
 7579     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7580     68/push 0/imm32
 7581     68/push 0/imm32
 7582     89/<- %edx 4/r32/esp
 7583     (tailor-exit-descriptor %edx 0x10)
 7584     #
 7585     (write _test-input-stream "fn foo {\n")
 7586     (write _test-input-stream "  var a/ebx: (addr array handle boolean) <- copy 0\n")
 7587     (write _test-input-stream "  var o/edi: (addr handle int) <- index a, 0\n")
 7588     (write _test-input-stream "}\n")
 7589     # convert
 7590     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7591     # registers except esp clobbered at this point
 7592     # restore ed
 7593     89/<- %edx 4/r32/esp
 7594     (flush _test-output-buffered-file)
 7595     (flush _test-error-buffered-file)
 7596 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7602     # check output
 7603     (check-stream-equal _test-output-stream  ""  "F - test-index-with-wrong-output-compound-type: output should be empty")
 7604     (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")
 7605     # check that stop(1) was called
 7606     (check-ints-equal *(edx+4) 2 "F - test-index-with-wrong-output-compound-type: exit status")
 7607     # don't restore from ebp
 7608     81 0/subop/add %esp 8/imm32
 7609     # . epilogue
 7610     5d/pop-to-ebp
 7611     c3/return
 7612 
 7613 test-index-with-no-inouts:
 7614     # . prologue
 7615     55/push-ebp
 7616     89/<- %ebp 4/r32/esp
 7617     # setup
 7618     (clear-stream _test-input-stream)
 7619     (clear-stream $_test-input-buffered-file->buffer)
 7620     (clear-stream _test-output-stream)
 7621     (clear-stream $_test-output-buffered-file->buffer)
 7622     (clear-stream _test-error-stream)
 7623     (clear-stream $_test-error-buffered-file->buffer)
 7624     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7625     68/push 0/imm32
 7626     68/push 0/imm32
 7627     89/<- %edx 4/r32/esp
 7628     (tailor-exit-descriptor %edx 0x10)
 7629     #
 7630     (write _test-input-stream "fn foo {\n")
 7631     (write _test-input-stream "  var c/ecx: (addr int) <- index\n")
 7632     (write _test-input-stream "}\n")
 7633     # convert
 7634     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7635     # registers except esp clobbered at this point
 7636     # restore ed
 7637     89/<- %edx 4/r32/esp
 7638     (flush _test-output-buffered-file)
 7639     (flush _test-error-buffered-file)
 7640 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7646     # check output
 7647     (check-stream-equal _test-output-stream  ""  "F - test-index-with-no-inouts: output should be empty")
 7648     (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")
 7649     # check that stop(1) was called
 7650     (check-ints-equal *(edx+4) 2 "F - test-index-with-no-inouts: exit status")
 7651     # don't restore from ebp
 7652     81 0/subop/add %esp 8/imm32
 7653     # . epilogue
 7654     5d/pop-to-ebp
 7655     c3/return
 7656 
 7657 test-index-with-too-few-inouts:
 7658     # . prologue
 7659     55/push-ebp
 7660     89/<- %ebp 4/r32/esp
 7661     # setup
 7662     (clear-stream _test-input-stream)
 7663     (clear-stream $_test-input-buffered-file->buffer)
 7664     (clear-stream _test-output-stream)
 7665     (clear-stream $_test-output-buffered-file->buffer)
 7666     (clear-stream _test-error-stream)
 7667     (clear-stream $_test-error-buffered-file->buffer)
 7668     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7669     68/push 0/imm32
 7670     68/push 0/imm32
 7671     89/<- %edx 4/r32/esp
 7672     (tailor-exit-descriptor %edx 0x10)
 7673     #
 7674     (write _test-input-stream "fn foo {\n")
 7675     (write _test-input-stream "  var a: (array int 3)\n")
 7676     (write _test-input-stream "  var c/ecx: (addr int) <- index a\n")
 7677     (write _test-input-stream "}\n")
 7678     # convert
 7679     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7680     # registers except esp clobbered at this point
 7681     # restore ed
 7682     89/<- %edx 4/r32/esp
 7683     (flush _test-output-buffered-file)
 7684     (flush _test-error-buffered-file)
 7685 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7691     # check output
 7692     (check-stream-equal _test-output-stream  ""  "F - test-index-with-too-few-inouts: output should be empty")
 7693     (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")
 7694     # check that stop(1) was called
 7695     (check-ints-equal *(edx+4) 2 "F - test-index-with-too-few-inouts: exit status")
 7696     # don't restore from ebp
 7697     81 0/subop/add %esp 8/imm32
 7698     # . epilogue
 7699     5d/pop-to-ebp
 7700     c3/return
 7701 
 7702 test-index-with-too-many-inouts:
 7703     # . prologue
 7704     55/push-ebp
 7705     89/<- %ebp 4/r32/esp
 7706     # setup
 7707     (clear-stream _test-input-stream)
 7708     (clear-stream $_test-input-buffered-file->buffer)
 7709     (clear-stream _test-output-stream)
 7710     (clear-stream $_test-output-buffered-file->buffer)
 7711     (clear-stream _test-error-stream)
 7712     (clear-stream $_test-error-buffered-file->buffer)
 7713     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7714     68/push 0/imm32
 7715     68/push 0/imm32
 7716     89/<- %edx 4/r32/esp
 7717     (tailor-exit-descriptor %edx 0x10)
 7718     #
 7719     (write _test-input-stream "fn foo {\n")
 7720     (write _test-input-stream "  var a: (array int 3)\n")
 7721     (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0, 0\n")
 7722     (write _test-input-stream "}\n")
 7723     # convert
 7724     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7725     # registers except esp clobbered at this point
 7726     # restore ed
 7727     89/<- %edx 4/r32/esp
 7728     (flush _test-output-buffered-file)
 7729     (flush _test-error-buffered-file)
 7730 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7736     # check output
 7737     (check-stream-equal _test-output-stream  ""  "F - test-index-with-too-many-inouts: output should be empty")
 7738     (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")
 7739     # check that stop(1) was called
 7740     (check-ints-equal *(edx+4) 2 "F - test-index-with-too-many-inouts: exit status")
 7741     # don't restore from ebp
 7742     81 0/subop/add %esp 8/imm32
 7743     # . epilogue
 7744     5d/pop-to-ebp
 7745     c3/return
 7746 
 7747 test-index-with-no-output:
 7748     # . prologue
 7749     55/push-ebp
 7750     89/<- %ebp 4/r32/esp
 7751     # setup
 7752     (clear-stream _test-input-stream)
 7753     (clear-stream $_test-input-buffered-file->buffer)
 7754     (clear-stream _test-output-stream)
 7755     (clear-stream $_test-output-buffered-file->buffer)
 7756     (clear-stream _test-error-stream)
 7757     (clear-stream $_test-error-buffered-file->buffer)
 7758     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7759     68/push 0/imm32
 7760     68/push 0/imm32
 7761     89/<- %edx 4/r32/esp
 7762     (tailor-exit-descriptor %edx 0x10)
 7763     #
 7764     (write _test-input-stream "fn foo {\n")
 7765     (write _test-input-stream "  var a: (array int 3)\n")
 7766     (write _test-input-stream "  index a, 0\n")
 7767     (write _test-input-stream "}\n")
 7768     # convert
 7769     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7770     # registers except esp clobbered at this point
 7771     # restore ed
 7772     89/<- %edx 4/r32/esp
 7773     (flush _test-output-buffered-file)
 7774     (flush _test-error-buffered-file)
 7775 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7781     # check output
 7782     (check-stream-equal _test-output-stream  ""  "F - test-index-with-no-output: output should be empty")
 7783     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: must have an output"  "F - test-index-with-no-output: error message")
 7784     # check that stop(1) was called
 7785     (check-ints-equal *(edx+4) 2 "F - test-index-with-no-output: exit status")
 7786     # don't restore from ebp
 7787     81 0/subop/add %esp 8/imm32
 7788     # . epilogue
 7789     5d/pop-to-ebp
 7790     c3/return
 7791 
 7792 test-index-with-too-many-outputs:
 7793     # . prologue
 7794     55/push-ebp
 7795     89/<- %ebp 4/r32/esp
 7796     # setup
 7797     (clear-stream _test-input-stream)
 7798     (clear-stream $_test-input-buffered-file->buffer)
 7799     (clear-stream _test-output-stream)
 7800     (clear-stream $_test-output-buffered-file->buffer)
 7801     (clear-stream _test-error-stream)
 7802     (clear-stream $_test-error-buffered-file->buffer)
 7803     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7804     68/push 0/imm32
 7805     68/push 0/imm32
 7806     89/<- %edx 4/r32/esp
 7807     (tailor-exit-descriptor %edx 0x10)
 7808     #
 7809     (write _test-input-stream "fn foo {\n")
 7810     (write _test-input-stream "  var a: (array int 3)\n")
 7811     (write _test-input-stream "  var b/eax: (addr int) <- copy 0\n")
 7812     (write _test-input-stream "  var c/ecx: (addr int) <- copy 0\n")
 7813     (write _test-input-stream "  b, c <- index a, 0\n")
 7814     (write _test-input-stream "}\n")
 7815     # convert
 7816     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7817     # registers except esp clobbered at this point
 7818     # restore ed
 7819     89/<- %edx 4/r32/esp
 7820     (flush _test-output-buffered-file)
 7821     (flush _test-error-buffered-file)
 7822 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7828     # check output
 7829     (check-stream-equal _test-output-stream  ""  "F - test-index-with-too-many-outputs: output should be empty")
 7830     (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")
 7831     # check that stop(1) was called
 7832     (check-ints-equal *(edx+4) 2 "F - test-index-with-too-many-outputs: exit status")
 7833     # don't restore from ebp
 7834     81 0/subop/add %esp 8/imm32
 7835     # . epilogue
 7836     5d/pop-to-ebp
 7837     c3/return
 7838 
 7839 #######################################################
 7840 # Parsing
 7841 #######################################################
 7842 
 7843 == data
 7844 
 7845 # Global state added to each var record when parsing a function
 7846 Next-block-index:  # (addr int)
 7847     1/imm32
 7848 
 7849 Curr-block-depth:  # (addr int)
 7850     1/imm32
 7851 
 7852 == code
 7853 
 7854 parse-mu:  # in: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
 7855     # pseudocode
 7856     #   var curr-function: (addr handle function) = Program->functions
 7857     #   var curr-signature: (addr handle function) = Program->signatures
 7858     #   var curr-type: (addr handle typeinfo) = Program->types
 7859     #   var line: (stream byte 512)
 7860     #   var word-slice: slice
 7861     #   while true                                  # line loop
 7862     #     clear-stream(line)
 7863     #     read-line-buffered(in, line)
 7864     #     if (line->write == 0) break               # end of file
 7865     #     word-slice = next-mu-token(line)
 7866     #     if slice-empty?(word-slice)               # end of line
 7867     #       continue
 7868     #     else if slice-starts-with?(word-slice, "#")  # comment
 7869     #       continue                                # end of line
 7870     #     else if slice-equal?(word-slice, "fn")
 7871     #       var new-function: (handle function) = allocate(function)
 7872     #       var vars: (stack live-var 256)
 7873     #       populate-mu-function-header(line, new-function, vars)
 7874     #       populate-mu-function-body(in, new-function, vars)
 7875     #       assert(vars->top == 0)
 7876     #       *curr-function = new-function
 7877     #       curr-function = &new-function->next
 7878     #     else if slice-equal?(word-slice, "sig")
 7879     #       var new-function: (handle function) = allocate(function)
 7880     #       populate-mu-function-signature(line, new-function)
 7881     #       *curr-signature = new-function
 7882     #       curr-signature = &new-function->next
 7883     #     else if slice-equal?(word-slice, "type")
 7884     #       word-slice = next-mu-token(line)
 7885     #       type-id = pos-or-insert-slice(Type-id, word-slice)
 7886     #       var new-type: (handle typeinfo) = find-or-create-typeinfo(type-id)
 7887     #       assert(next-word(line) == "{")
 7888     #       populate-mu-type(in, new-type)
 7889     #     else
 7890     #       abort()
 7891     #
 7892     # . prologue
 7893     55/push-ebp
 7894     89/<- %ebp 4/r32/esp
 7895     # var curr-signature: (addr handle function) at *(ebp-4)
 7896     68/push _Program-signatures/imm32
 7897     # . save registers
 7898     50/push-eax
 7899     51/push-ecx
 7900     52/push-edx
 7901     53/push-ebx
 7902     56/push-esi
 7903     57/push-edi
 7904     # var line/ecx: (stream byte 512)
 7905     81 5/subop/subtract %esp 0x200/imm32
 7906     68/push 0x200/imm32/size
 7907     68/push 0/imm32/read
 7908     68/push 0/imm32/write
 7909     89/<- %ecx 4/r32/esp
 7910     # var word-slice/edx: slice
 7911     68/push 0/imm32/end
 7912     68/push 0/imm32/start
 7913     89/<- %edx 4/r32/esp
 7914     # var curr-function/edi: (addr handle function)
 7915     bf/copy-to-edi _Program-functions/imm32
 7916     # var vars/ebx: (stack live-var 256)
 7917     81 5/subop/subtract %esp 0xc00/imm32
 7918     68/push 0xc00/imm32/size
 7919     68/push 0/imm32/top
 7920     89/<- %ebx 4/r32/esp
 7921     {
 7922 $parse-mu:line-loop:
 7923       (clear-stream %ecx)
 7924       (read-line-buffered *(ebp+8) %ecx)
 7925       # if (line->write == 0) break
 7926       81 7/subop/compare *ecx 0/imm32
 7927       0f 84/jump-if-= break/disp32
 7928 +--  6 lines: #?       # dump line ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7934       (next-mu-token %ecx %edx)
 7935       # if slice-empty?(word-slice) continue
 7936       (slice-empty? %edx)  # => eax
 7937       3d/compare-eax-and 0/imm32/false
 7938       0f 85/jump-if-!= loop/disp32
 7939       # if (*word-slice->start == "#") continue
 7940       # . eax = *word-slice->start
 7941       8b/-> *edx 0/r32/eax
 7942       8a/copy-byte *eax 0/r32/AL
 7943       81 4/subop/and %eax 0xff/imm32
 7944       # . if (eax == '#') continue
 7945       3d/compare-eax-and 0x23/imm32/hash
 7946       0f 84/jump-if-= loop/disp32
 7947       # if (slice-equal?(word-slice, "fn")) parse a function
 7948       {
 7949 $parse-mu:fn:
 7950         (slice-equal? %edx "fn")  # => eax
 7951         3d/compare-eax-and 0/imm32/false
 7952         0f 84/jump-if-= break/disp32
 7953         # var new-function/esi: (handle function)
 7954         68/push 0/imm32
 7955         68/push 0/imm32
 7956         89/<- %esi 4/r32/esp
 7957         # populate-mu-function(line, in, vars, new-function)
 7958         (allocate Heap *Function-size %esi)
 7959         # var new-function-addr/eax: (addr function)
 7960         (lookup *esi *(esi+4))  # => eax
 7961         # initialize vars
 7962         (clear-stack %ebx)
 7963         #
 7964         (populate-mu-function-header %ecx %eax %ebx *(ebp+0xc) *(ebp+0x10))
 7965         (populate-mu-function-body *(ebp+8) %eax %ebx *(ebp+0xc) *(ebp+0x10))
 7966         # *curr-function = new-function
 7967         8b/-> *esi 0/r32/eax
 7968         89/<- *edi 0/r32/eax
 7969         8b/-> *(esi+4) 0/r32/eax
 7970         89/<- *(edi+4) 0/r32/eax
 7971         # curr-function = &new-function->next
 7972         # . var tmp/eax: (addr function) = lookup(new-function)
 7973         (lookup *esi *(esi+4))  # => eax
 7974         # . curr-function = &tmp->next
 7975         8d/copy-address *(eax+0x20) 7/r32/edi  # Function-next
 7976         # reclaim new-function
 7977         81 0/subop/add %esp 8/imm32
 7978         #
 7979         e9/jump $parse-mu:line-loop/disp32
 7980       }
 7981       # if (slice-equal?(word-slice, "sig")) parse a function signature
 7982       # Function signatures are for providing types to SubX functions.
 7983       {
 7984 $parse-mu:sig:
 7985         (slice-equal? %edx "sig")  # => eax
 7986         3d/compare-eax-and 0/imm32/false
 7987         0f 84/jump-if-= break/disp32
 7988         # edi = curr-function
 7989         57/push-edi
 7990         8b/-> *(ebp-4) 7/r32/edi
 7991         # var new-function/esi: (handle function)
 7992         68/push 0/imm32
 7993         68/push 0/imm32
 7994         89/<- %esi 4/r32/esp
 7995         # populate-mu-function(line, in, vars, new-function)
 7996         (allocate Heap *Function-size %esi)
 7997         # var new-function-addr/eax: (addr function)
 7998         (lookup *esi *(esi+4))  # => eax
 7999         #
 8000         (populate-mu-function-signature %ecx %eax *(ebp+0xc) *(ebp+0x10))
 8001         # *curr-signature = new-function
 8002         8b/-> *esi 0/r32/eax
 8003         89/<- *edi 0/r32/eax
 8004         8b/-> *(esi+4) 0/r32/eax
 8005         89/<- *(edi+4) 0/r32/eax
 8006         # curr-signature = &new-function->next
 8007         # . var tmp/eax: (addr function) = lookup(new-function)
 8008         (lookup *esi *(esi+4))  # => eax
 8009         # . curr-function = &tmp->next
 8010         8d/copy-address *(eax+0x20) 7/r32/edi  # Function-next
 8011         # reclaim new-function
 8012         81 0/subop/add %esp 8/imm32
 8013         # save curr-function
 8014         89/<- *(ebp-4) 7/r32/edi
 8015         # restore edi
 8016         5f/pop-to-edi
 8017         #
 8018         e9/jump $parse-mu:line-loop/disp32
 8019       }
 8020       # if (slice-equal?(word-slice, "type")) parse a type (struct/record) definition
 8021       {
 8022 $parse-mu:type:
 8023         (slice-equal? %edx "type")  # => eax
 8024         3d/compare-eax-and 0/imm32
 8025         0f 84/jump-if-= break/disp32
 8026         (next-mu-token %ecx %edx)
 8027         # var type-id/eax: int
 8028         (pos-or-insert-slice Type-id %edx)  # => eax
 8029         # spill
 8030         51/push-ecx
 8031         # var new-type/ecx: (handle typeinfo)
 8032         68/push 0/imm32
 8033         68/push 0/imm32
 8034         89/<- %ecx 4/r32/esp
 8035         (find-or-create-typeinfo %eax %ecx)
 8036         #
 8037         (lookup *ecx *(ecx+4))  # => eax
 8038         # TODO: ensure that 'line' has nothing else but '{'
 8039 #? (dump-typeinfos "=== aaa\n")
 8040         (populate-mu-type *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))  # => eax
 8041 #? (dump-typeinfos "=== zzz\n")
 8042         # reclaim new-type
 8043         81 0/subop/add %esp 8/imm32
 8044         # restore
 8045         59/pop-to-ecx
 8046         e9/jump $parse-mu:line-loop/disp32
 8047       }
 8048       # otherwise abort
 8049       e9/jump $parse-mu:error1/disp32
 8050     } # end line loop
 8051 $parse-mu:end:
 8052     # . reclaim locals
 8053     81 0/subop/add %esp 0x20c/imm32  # line
 8054     81 0/subop/add %esp 0xc08/imm32  # vars
 8055     81 0/subop/add %esp 8/imm32
 8056     # . restore registers
 8057     5f/pop-to-edi
 8058     5e/pop-to-esi
 8059     5b/pop-to-ebx
 8060     5a/pop-to-edx
 8061     59/pop-to-ecx
 8062     58/pop-to-eax
 8063     # . reclaim local
 8064     81 0/subop/add %esp 4/imm32
 8065     # . epilogue
 8066     89/<- %esp 5/r32/ebp
 8067     5d/pop-to-ebp
 8068     c3/return
 8069 
 8070 $parse-mu:error1:
 8071     # error("unexpected top-level command: " word-slice "\n")
 8072     (write-buffered *(ebp+0xc) "unexpected top-level command: ")
 8073     (write-slice-buffered *(ebp+0xc) %edx)
 8074     (write-buffered *(ebp+0xc) "\n")
 8075     (flush *(ebp+0xc))
 8076     (stop *(ebp+0x10) 1)
 8077     # never gets here
 8078 
 8079 $parse-mu:error2:
 8080     # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n")
 8081     (write-int32-hex-buffered *(ebp+0xc) *ebx)
 8082     (write-buffered *(ebp+0xc) " vars not reclaimed after fn '")
 8083     (write-slice-buffered *(ebp+0xc) *eax)  # Function-name
 8084     (write-buffered *(ebp+0xc) "'\n")
 8085     (flush *(ebp+0xc))
 8086     (stop *(ebp+0x10) 1)
 8087     # never gets here
 8088 
 8089 # scenarios considered:
 8090 # ✗ fn foo  # no block
 8091 # ✓ fn foo {
 8092 # ✗ fn foo { {
 8093 # ✗ fn foo { }
 8094 # ✗ fn foo { } {
 8095 # ✗ fn foo x {
 8096 # ✗ fn foo x: {
 8097 # ✓ fn foo x: int {
 8098 # ✓ fn foo x: int {
 8099 # ✓ fn foo x: int -> y/eax: int {
 8100 # TODO:
 8101 #   disallow outputs of type `(... addr ...)`
 8102 #   disallow inputs of type `(... addr ... addr ...)`
 8103 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)
 8104     # pseudocode:
 8105     #   var word-slice: slice
 8106     #   next-mu-token(first-line, word-slice)
 8107     #   if slice-empty?(word-slice) abort
 8108     #   assert(word-slice not in '{' '}' '->')
 8109     #   out->name = slice-to-string(word-slice)
 8110     #   ## inouts
 8111     #   while true
 8112     #     word-slice = next-mu-token(first-line)
 8113     #     if slice-empty?(word-slice) abort
 8114     #     if (word-slice == '{') goto done
 8115     #     if (word-slice == '->') break
 8116     #     assert(word-slice != '}')
 8117     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 8118     #     assert(v->register == null)
 8119     #     # v->block-depth is implicitly 0
 8120     #     out->inouts = append(v, out->inouts)
 8121     #     push(vars, {v, false})
 8122     #   ## outputs
 8123     #   while true
 8124     #     word-slice = next-mu-token(first-line)
 8125     #     if slice-empty?(word-slice) abort
 8126     #     if (word-slice == '{') break
 8127     #     assert(word-slice not in '}' '->')
 8128     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 8129     #     assert(v->register != null)
 8130     #     out->outputs = append(v, out->outputs)
 8131     #   done:
 8132     #
 8133     # . prologue
 8134     55/push-ebp
 8135     89/<- %ebp 4/r32/esp
 8136     # . save registers
 8137     50/push-eax
 8138     51/push-ecx
 8139     52/push-edx
 8140     53/push-ebx
 8141     57/push-edi
 8142     # edi = out
 8143     8b/-> *(ebp+0xc) 7/r32/edi
 8144     # var word-slice/ecx: slice
 8145     68/push 0/imm32/end
 8146     68/push 0/imm32/start
 8147     89/<- %ecx 4/r32/esp
 8148     # var v/ebx: (handle var)
 8149     68/push 0/imm32
 8150     68/push 0/imm32
 8151     89/<- %ebx 4/r32/esp
 8152     # read function name
 8153     (next-mu-token *(ebp+8) %ecx)
 8154     # error checking
 8155     # if slice-empty?(word-slice) abort
 8156     (slice-empty? %ecx)  # => eax
 8157     3d/compare-eax-and 0/imm32/false
 8158     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 8159     # if (word-slice == '{') abort
 8160     (slice-equal? %ecx "{")   # => eax
 8161     3d/compare-eax-and 0/imm32/false
 8162     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 8163     # if (word-slice == '->') abort
 8164     (slice-equal? %ecx "->")   # => eax
 8165     3d/compare-eax-and 0/imm32/false
 8166     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 8167     # if (word-slice == '}') abort
 8168     (slice-equal? %ecx "}")   # => eax
 8169     3d/compare-eax-and 0/imm32/false
 8170     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 8171     # save function name
 8172     (slice-to-string Heap %ecx %edi)  # Function-name
 8173     # save function inouts
 8174     {
 8175 $populate-mu-function-header:check-for-inout:
 8176       (next-mu-token *(ebp+8) %ecx)
 8177       # if slice-empty?(word-slice) abort
 8178       (slice-empty? %ecx)  # => eax
 8179       3d/compare-eax-and 0/imm32/false
 8180       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 8181       # if (word-slice == '{') goto done
 8182       (slice-equal? %ecx "{")   # => eax
 8183       3d/compare-eax-and 0/imm32/false
 8184       0f 85/jump-if-!= $populate-mu-function-header:done/disp32
 8185       # if (word-slice == '->') break
 8186       (slice-equal? %ecx "->")   # => eax
 8187       3d/compare-eax-and 0/imm32/false
 8188       0f 85/jump-if-!= break/disp32
 8189       # if (word-slice == '}') abort
 8190       (slice-equal? %ecx "}")   # => eax
 8191       3d/compare-eax-and 0/imm32/false
 8192       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 8193       # v = parse-var-with-type(word-slice, first-line)
 8194       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x14) *(ebp+0x18))
 8195       # assert(v->register == null)
 8196       # . eax: (addr var) = lookup(v)
 8197       (lookup *ebx *(ebx+4))  # => eax
 8198       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 8199       0f 85/jump-if-!= $populate-mu-function-header:error2/disp32
 8200       # v->block-depth is implicitly 0
 8201       #
 8202       # out->inouts = append(v, out->inouts)
 8203       8d/copy-address *(edi+8) 0/r32/eax  # Function-inouts
 8204       (append-list Heap  *ebx *(ebx+4)  *(edi+8) *(edi+0xc)  %eax)  # Function-inouts, Function-inouts
 8205       # push(vars, {v, false})
 8206       (push *(ebp+0x10) *ebx)
 8207       (push *(ebp+0x10) *(ebx+4))
 8208       (push *(ebp+0x10) 0)  # false
 8209       #
 8210       e9/jump loop/disp32
 8211     }
 8212     # save function outputs
 8213     {
 8214 $populate-mu-function-header:check-for-out:
 8215       (next-mu-token *(ebp+8) %ecx)
 8216       # if slice-empty?(word-slice) abort
 8217       (slice-empty? %ecx)  # => eax
 8218       3d/compare-eax-and 0/imm32/false
 8219       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 8220       # if (word-slice == '{') break
 8221       (slice-equal? %ecx "{")   # => eax
 8222       3d/compare-eax-and 0/imm32/false
 8223       0f 85/jump-if-!= break/disp32
 8224       # if (word-slice == '->') abort
 8225       (slice-equal? %ecx "->")   # => eax
 8226       3d/compare-eax-and 0/imm32/false
 8227       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 8228       # if (word-slice == '}') abort
 8229       (slice-equal? %ecx "}")   # => eax
 8230       3d/compare-eax-and 0/imm32/false
 8231       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 8232       # v = parse-var-with-type(word-slice, first-line)
 8233       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x14) *(ebp+0x18))
 8234       # assert(var->register != null)
 8235       # . eax: (addr var) = lookup(v)
 8236       (lookup *ebx *(ebx+4))  # => eax
 8237       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 8238       0f 84/jump-if-= $populate-mu-function-header:error3/disp32
 8239       # out->outputs = append(v, out->outputs)
 8240       8d/copy-address *(edi+0x10) 0/r32/eax  # Function-outputs
 8241       (append-list Heap  *ebx *(ebx+4)  *(edi+0x10) *(edi+0x14)  %eax)  # Function-outputs, Function-outputs
 8242       #
 8243       e9/jump loop/disp32
 8244     }
 8245 $populate-mu-function-header:done:
 8246     (check-no-tokens-left *(ebp+8))
 8247 $populate-mu-function-header:end:
 8248     # . reclaim locals
 8249     81 0/subop/add %esp 0x10/imm32
 8250     # . restore registers
 8251     5f/pop-to-edi
 8252     5b/pop-to-ebx
 8253     5a/pop-to-edx
 8254     59/pop-to-ecx
 8255     58/pop-to-eax
 8256     # . epilogue
 8257     89/<- %esp 5/r32/ebp
 8258     5d/pop-to-ebp
 8259     c3/return
 8260 
 8261 $populate-mu-function-header:error1:
 8262     # error("function header not in form 'fn <name> {'")
 8263     (write-buffered *(ebp+0x14) "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '")
 8264     (flush *(ebp+0x14))
 8265     (rewind-stream *(ebp+8))
 8266     (write-stream-data *(ebp+0x14) *(ebp+8))
 8267     (write-buffered *(ebp+0x14) "'\n")
 8268     (flush *(ebp+0x14))
 8269     (stop *(ebp+0x18) 1)
 8270     # never gets here
 8271 
 8272 $populate-mu-function-header:error2:
 8273     # error("fn " fn ": function inout '" var "' cannot be in a register")
 8274     (write-buffered *(ebp+0x14) "fn ")
 8275     50/push-eax
 8276     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 8277     (write-buffered *(ebp+0x14) %eax)
 8278     58/pop-to-eax
 8279     (write-buffered *(ebp+0x14) ": function inout '")
 8280     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 8281     (write-buffered *(ebp+0x10) %eax)
 8282     (write-buffered *(ebp+0x14) "' cannot be in a register")
 8283     (flush *(ebp+0x14))
 8284     (stop *(ebp+0x18) 1)
 8285     # never gets here
 8286 
 8287 $populate-mu-function-header:error3:
 8288     # error("fn " fn ": function output '" var "' must be in a register")
 8289     (write-buffered *(ebp+0x14) "fn ")
 8290     50/push-eax
 8291     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 8292     (write-buffered *(ebp+0x14) %eax)
 8293     58/pop-to-eax
 8294     (write-buffered *(ebp+0x14) ": function output '")
 8295     (lookup *ebx *(ebx+4))  # => eax
 8296     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 8297     (write-buffered *(ebp+0x14) %eax)
 8298     (write-buffered *(ebp+0x14) "' must be in a register, in instruction '")
 8299     (rewind-stream *(ebp+8))
 8300     (write-stream-data *(ebp+0x14) *(ebp+8))
 8301     (write-buffered *(ebp+0x14) "'\n")
 8302     (flush *(ebp+0x14))
 8303     (stop *(ebp+0x18) 1)
 8304     # never gets here
 8305 
 8306 # scenarios considered:
 8307 # ✓ fn foo
 8308 # ✗ fn foo {
 8309 # ✓ fn foo x
 8310 # ✓ fn foo x: int
 8311 # ✓ fn foo x: int -> y/eax: int
 8312 # TODO:
 8313 #   disallow outputs of type `(... addr ...)`
 8314 #   disallow inputs of type `(... addr ... addr ...)`
 8315 populate-mu-function-signature:  # first-line: (addr stream byte), out: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
 8316     # pseudocode:
 8317     #   var word-slice: slice
 8318     #   next-mu-token(first-line, word-slice)
 8319     #   assert(word-slice not in '{' '}' '->')
 8320     #   out->name = slice-to-string(word-slice)
 8321     #   ## inouts
 8322     #   while true
 8323     #     word-slice = next-mu-token(first-line)
 8324     #     if slice-empty?(word-slice) break
 8325     #     if (word-slice == '->') break
 8326     #     assert(word-slice not in '{' '}')
 8327     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 8328     #     assert(v->register == null)
 8329     #     # v->block-depth is implicitly 0
 8330     #     out->inouts = append(v, out->inouts)
 8331     #   ## outputs
 8332     #   while true
 8333     #     word-slice = next-mu-token(first-line)
 8334     #     if slice-empty?(word-slice) break
 8335     #     assert(word-slice not in '{' '}' '->')
 8336     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 8337     #     assert(v->register != null)
 8338     #     out->outputs = append(v, out->outputs)
 8339     #
 8340     # . prologue
 8341     55/push-ebp
 8342     89/<- %ebp 4/r32/esp
 8343     # . save registers
 8344     50/push-eax
 8345     51/push-ecx
 8346     52/push-edx
 8347     53/push-ebx
 8348     57/push-edi
 8349     # edi = out
 8350     8b/-> *(ebp+0xc) 7/r32/edi
 8351     # var word-slice/ecx: slice
 8352     68/push 0/imm32/end
 8353     68/push 0/imm32/start
 8354     89/<- %ecx 4/r32/esp
 8355     # var v/ebx: (handle var)
 8356     68/push 0/imm32
 8357     68/push 0/imm32
 8358     89/<- %ebx 4/r32/esp
 8359     # read function name
 8360     (next-mu-token *(ebp+8) %ecx)
 8361     # error checking
 8362     # if (word-slice == '{') abort
 8363     (slice-equal? %ecx "{")   # => eax
 8364     3d/compare-eax-and 0/imm32/false
 8365     0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 8366     # if (word-slice == '->') abort
 8367     (slice-equal? %ecx "->")   # => eax
 8368     3d/compare-eax-and 0/imm32/false
 8369     0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 8370     # if (word-slice == '}') abort
 8371     (slice-equal? %ecx "}")   # => eax
 8372     3d/compare-eax-and 0/imm32/false
 8373     0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 8374     # save function name
 8375     (slice-to-string Heap %ecx %edi)  # Function-name
 8376     # save function inouts
 8377     {
 8378 $populate-mu-function-signature:check-for-inout:
 8379       (next-mu-token *(ebp+8) %ecx)
 8380       (slice-empty? %ecx)  # => eax
 8381       3d/compare-eax-and 0/imm32/false
 8382       0f 85/jump-if-!= break/disp32
 8383       # if (word-slice == '->') break
 8384       (slice-equal? %ecx "->")   # => eax
 8385       3d/compare-eax-and 0/imm32/false
 8386       0f 85/jump-if-!= break/disp32
 8387       # if (word-slice == '{') abort
 8388       (slice-equal? %ecx "{")   # => eax
 8389       3d/compare-eax-and 0/imm32/false
 8390       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 8391       # if (word-slice == '}') abort
 8392       (slice-equal? %ecx "}")   # => eax
 8393       3d/compare-eax-and 0/imm32/false
 8394       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 8395       # v = parse-var-with-type(word-slice, first-line)
 8396       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x10) *(ebp+0x14))
 8397       # assert(v->register == null)
 8398       # . eax: (addr var) = lookup(v)
 8399       (lookup *ebx *(ebx+4))  # => eax
 8400       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 8401       0f 85/jump-if-!= $populate-mu-function-signature:error2/disp32
 8402       # v->block-depth is implicitly 0
 8403       #
 8404       # out->inouts = append(v, out->inouts)
 8405       8d/copy-address *(edi+8) 0/r32/eax  # Function-inouts
 8406       (append-list Heap  *ebx *(ebx+4)  *(edi+8) *(edi+0xc)  %eax)  # Function-inouts, Function-inouts
 8407       #
 8408       e9/jump loop/disp32
 8409     }
 8410     # save function outputs
 8411     {
 8412 $populate-mu-function-signature:check-for-out:
 8413       (next-mu-token *(ebp+8) %ecx)
 8414       (slice-empty? %ecx)  # => eax
 8415       3d/compare-eax-and 0/imm32/false
 8416       0f 85/jump-if-!= break/disp32
 8417       # if (word-slice == '{') abort
 8418       (slice-equal? %ecx "{")   # => eax
 8419       3d/compare-eax-and 0/imm32/false
 8420       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 8421       # if (word-slice == '->') abort
 8422       (slice-equal? %ecx "->")   # => eax
 8423       3d/compare-eax-and 0/imm32/false
 8424       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 8425       # if (word-slice == '}') abort
 8426       (slice-equal? %ecx "}")   # => eax
 8427       3d/compare-eax-and 0/imm32/false
 8428       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 8429       # v = parse-var-with-type(word-slice, first-line)
 8430       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x10) *(ebp+0x14))
 8431       # assert(var->register != null)
 8432       # . eax: (addr var) = lookup(v)
 8433       (lookup *ebx *(ebx+4))  # => eax
 8434       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 8435       0f 84/jump-if-= $populate-mu-function-signature:error3/disp32
 8436       # out->outputs = append(v, out->outputs)
 8437       8d/copy-address *(edi+0x10) 0/r32/eax  # Function-outputs
 8438       (append-list Heap  *ebx *(ebx+4)  *(edi+0x10) *(edi+0x14)  %eax)  # Function-outputs, Function-outputs
 8439       #
 8440       e9/jump loop/disp32
 8441     }
 8442 $populate-mu-function-signature:done:
 8443     (check-no-tokens-left *(ebp+8))
 8444 $populate-mu-function-signature:end:
 8445     # . reclaim locals
 8446     81 0/subop/add %esp 0x10/imm32
 8447     # . restore registers
 8448     5f/pop-to-edi
 8449     5b/pop-to-ebx
 8450     5a/pop-to-edx
 8451     59/pop-to-ecx
 8452     58/pop-to-eax
 8453     # . epilogue
 8454     89/<- %esp 5/r32/ebp
 8455     5d/pop-to-ebp
 8456     c3/return
 8457 
 8458 $populate-mu-function-signature:error1:
 8459     # error("function signature not in form 'fn <name> {'")
 8460     (write-buffered *(ebp+0x10) "function signature not in form 'fn <name> [inouts] [-> outputs] {' -- '")
 8461     (flush *(ebp+0x10))
 8462     (rewind-stream *(ebp+8))
 8463     (write-stream-data *(ebp+0x10) *(ebp+8))
 8464     (write-buffered *(ebp+0x10) "'\n")
 8465     (flush *(ebp+0x10))
 8466     (stop *(ebp+0x14) 1)
 8467     # never gets here
 8468 
 8469 $populate-mu-function-signature:error2:
 8470     # error("fn " fn ": function inout '" var "' cannot be in a register")
 8471     (write-buffered *(ebp+0x10) "fn ")
 8472     50/push-eax
 8473     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 8474     (write-buffered *(ebp+0x10) %eax)
 8475     58/pop-to-eax
 8476     (write-buffered *(ebp+0x10) ": function inout '")
 8477     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 8478     (write-buffered *(ebp+0x10) %eax)
 8479     (write-buffered *(ebp+0x10) "' cannot be in a register")
 8480     (flush *(ebp+0x10))
 8481     (stop *(ebp+0x14) 1)
 8482     # never gets here
 8483 
 8484 $populate-mu-function-signature:error3:
 8485     # error("fn " fn ": function output '" var "' must be in a register")
 8486     (write-buffered *(ebp+0x10) "fn ")
 8487     50/push-eax
 8488     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 8489     (write-buffered *(ebp+0x10) %eax)
 8490     58/pop-to-eax
 8491     (write-buffered *(ebp+0x10) ": function output '")
 8492     (lookup *ebx *(ebx+4))  # => eax
 8493     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 8494     (write-buffered *(ebp+0x10) %eax)
 8495     (write-buffered *(ebp+0x10) "' must be in a register, in instruction '")
 8496     (rewind-stream *(ebp+8))
 8497     (write-stream-data *(ebp+0x10) *(ebp+8))
 8498     (write-buffered *(ebp+0x10) "'\n")
 8499     (flush *(ebp+0x10))
 8500     (stop *(ebp+0x14) 1)
 8501     # never gets here
 8502 
 8503 test-function-header-with-arg:
 8504     # . prologue
 8505     55/push-ebp
 8506     89/<- %ebp 4/r32/esp
 8507     # setup
 8508     8b/-> *Primitive-type-ids 0/r32/eax
 8509     89/<- *Type-id 0/r32/eax  # stream-write
 8510     (clear-stream _test-input-stream)
 8511     (write _test-input-stream "foo n: int {\n")
 8512     # var result/ecx: function
 8513     2b/subtract *Function-size 4/r32/esp
 8514     89/<- %ecx 4/r32/esp
 8515     (zero-out %ecx *Function-size)
 8516     # var vars/ebx: (stack live-var 16)
 8517     81 5/subop/subtract %esp 0xc0/imm32
 8518     68/push 0xc0/imm32/size
 8519     68/push 0/imm32/top
 8520     89/<- %ebx 4/r32/esp
 8521     # convert
 8522     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 8523     # check result->name
 8524     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 8525     (check-strings-equal %eax "foo" "F - test-function-header-with-arg/name")
 8526     # var v/edx: (addr var) = result->inouts->value
 8527     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 8528     (lookup *eax *(eax+4))  # List-value List-value => eax
 8529     89/<- %edx 0/r32/eax
 8530     # check v->name
 8531     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 8532     (check-strings-equal %eax "n" "F - test-function-header-with-arg/inout:0")
 8533     # check v->type
 8534     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 8535     (check-ints-equal *eax 1 "F - test-function-header-with-arg/inout:0/type:0")  # Type-tree-is-atom
 8536     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-arg/inout:0/type:1")  # Type-tree-value
 8537     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-arg/inout:0/type:2")  # Type-tree-right
 8538     # . epilogue
 8539     89/<- %esp 5/r32/ebp
 8540     5d/pop-to-ebp
 8541     c3/return
 8542 
 8543 test-function-header-with-multiple-args:
 8544     # . prologue
 8545     55/push-ebp
 8546     89/<- %ebp 4/r32/esp
 8547     # setup
 8548     8b/-> *Primitive-type-ids 0/r32/eax
 8549     89/<- *Type-id 0/r32/eax  # stream-write
 8550     (clear-stream _test-input-stream)
 8551     (write _test-input-stream "foo a: int, b: int c: int {\n")
 8552     # result/ecx: function
 8553     2b/subtract *Function-size 4/r32/esp
 8554     89/<- %ecx 4/r32/esp
 8555     (zero-out %ecx *Function-size)
 8556     # var vars/ebx: (stack live-var 16)
 8557     81 5/subop/subtract %esp 0xc0/imm32
 8558     68/push 0xc0/imm32/size
 8559     68/push 0/imm32/top
 8560     89/<- %ebx 4/r32/esp
 8561     # convert
 8562     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 8563     # check result->name
 8564     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 8565     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args/name")
 8566     # var inouts/edx: (addr list var) = lookup(result->inouts)
 8567     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 8568     89/<- %edx 0/r32/eax
 8569 $test-function-header-with-multiple-args:inout0:
 8570     # var v/ebx: (addr var) = lookup(inouts->value)
 8571     (lookup *edx *(edx+4))  # List-value List-value => eax
 8572     89/<- %ebx 0/r32/eax
 8573     # check v->name
 8574     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 8575     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args/inout:0")  # Var-name
 8576     # check v->type
 8577     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 8578     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:0/type:0")  # Type-tree-is-atom
 8579     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:0/type:1")  # Type-tree-value
 8580     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:0/type:2")  # Type-tree-right
 8581 $test-function-header-with-multiple-args:inout1:
 8582     # inouts = lookup(inouts->next)
 8583     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 8584     89/<- %edx 0/r32/eax
 8585     # v = lookup(inouts->value)
 8586     (lookup *edx *(edx+4))  # List-value List-value => eax
 8587     89/<- %ebx 0/r32/eax
 8588     # check v->name
 8589     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 8590     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args/inout:1")  # Var-name
 8591     # check v->type
 8592     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 8593     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:1/type:0")  # Type-tree-is-atom
 8594     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:1/type:1")  # Type-tree-value
 8595     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:1/type:2")  # Type-tree-right
 8596 $test-function-header-with-multiple-args:inout2:
 8597     # inouts = lookup(inouts->next)
 8598     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 8599     89/<- %edx 0/r32/eax
 8600     # v = lookup(inouts->value)
 8601     (lookup *edx *(edx+4))  # List-value List-value => eax
 8602     89/<- %ebx 0/r32/eax
 8603     # check v->name
 8604     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 8605     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args/inout:2")  # Var-name
 8606     # check v->type
 8607     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 8608     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:2/type:0")  # Type-tree-is-atom
 8609     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:2/type:1")  # Type-tree-value
 8610     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:2/type:2")  # Type-tree-right
 8611     # . epilogue
 8612     89/<- %esp 5/r32/ebp
 8613     5d/pop-to-ebp
 8614     c3/return
 8615 
 8616 test-function-header-with-multiple-args-and-outputs:
 8617     # . prologue
 8618     55/push-ebp
 8619     89/<- %ebp 4/r32/esp
 8620     # setup
 8621     8b/-> *Primitive-type-ids 0/r32/eax
 8622     89/<- *Type-id 0/r32/eax  # stream-write
 8623     (clear-stream _test-input-stream)
 8624     (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx: int {\n")
 8625     # result/ecx: function
 8626     2b/subtract *Function-size 4/r32/esp
 8627     89/<- %ecx 4/r32/esp
 8628     (zero-out %ecx *Function-size)
 8629     # var vars/ebx: (stack live-var 16)
 8630     81 5/subop/subtract %esp 0xc0/imm32
 8631     68/push 0xc0/imm32/size
 8632     68/push 0/imm32/top
 8633     89/<- %ebx 4/r32/esp
 8634     # convert
 8635     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 8636     # check result->name
 8637     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 8638     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args-and-outputs/name")
 8639     # var inouts/edx: (addr list var) = lookup(result->inouts)
 8640     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 8641     89/<- %edx 0/r32/eax
 8642 $test-function-header-with-multiple-args-and-outputs:inout0:
 8643     # var v/ebx: (addr var) = lookup(inouts->value)
 8644     (lookup *edx *(edx+4))  # List-value List-value => eax
 8645     89/<- %ebx 0/r32/eax
 8646     # check v->name
 8647     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 8648     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args-and-outputs/inout:0")
 8649     # check v->type
 8650     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 8651     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:0")  # Type-tree-is-atom
 8652     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1")  # Type-tree-value
 8653     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:2")  # Type-tree-right
 8654 $test-function-header-with-multiple-args-and-outputs:inout1:
 8655     # inouts = lookup(inouts->next)
 8656     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 8657     89/<- %edx 0/r32/eax
 8658     # v = lookup(inouts->value)
 8659     (lookup *edx *(edx+4))  # List-value List-value => eax
 8660     89/<- %ebx 0/r32/eax
 8661     # check v->name
 8662     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 8663     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args-and-outputs/inout:1")
 8664     # check v->type
 8665     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 8666     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:0")  # Type-tree-is-atom
 8667     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1")  # Type-tree-value
 8668     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:2")  # Type-tree-right
 8669 $test-function-header-with-multiple-args-and-outputs:inout2:
 8670     # inouts = lookup(inouts->next)
 8671     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 8672     89/<- %edx 0/r32/eax
 8673     # v = lookup(inouts->value)
 8674     (lookup *edx *(edx+4))  # List-value List-value => eax
 8675     89/<- %ebx 0/r32/eax
 8676     # check v->name
 8677     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 8678     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args-and-outputs/inout:2")
 8679     # check v->type
 8680     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 8681     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:0")  # Type-tree-is-atom
 8682     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1")  # Type-tree-value
 8683     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:2")  # Type-tree-right
 8684 $test-function-header-with-multiple-args-and-outputs:out0:
 8685     # var outputs/edx: (addr list var) = lookup(result->outputs)
 8686     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
 8687     89/<- %edx 0/r32/eax
 8688     # v = lookup(outputs->value)
 8689     (lookup *edx *(edx+4))  # List-value List-value => eax
 8690     89/<- %ebx 0/r32/eax
 8691     # check v->name
 8692     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 8693     (check-strings-equal %eax "x" "F - test-function-header-with-multiple-args-and-outputs/output:0")
 8694     # check v->register
 8695     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 8696     (check-strings-equal %eax "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register")
 8697     # check v->type
 8698     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 8699     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:0")  # Type-tree-is-atom
 8700     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1")  # Type-tree-value
 8701     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:2")  # Type-tree-right
 8702 $test-function-header-with-multiple-args-and-outputs:out1:
 8703     # outputs = lookup(outputs->next)
 8704     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 8705     89/<- %edx 0/r32/eax
 8706     # v = lookup(inouts->value)
 8707     (lookup *edx *(edx+4))  # List-value List-value => eax
 8708     89/<- %ebx 0/r32/eax
 8709     # check v->name
 8710     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 8711     (check-strings-equal %eax "y" "F - test-function-header-with-multiple-args-and-outputs/output:1")
 8712     # check v->register
 8713     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 8714     (check-strings-equal %eax "edx" "F - test-function-header-with-multiple-args-and-outputs/output:1/register")
 8715     # check v->type
 8716     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 8717     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:0")  # Type-tree-is-atom
 8718     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1")  # Type-tree-value
 8719     (check-ints-equal *(eax+0c) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:2")  # Type-tree-right
 8720     # . epilogue
 8721     89/<- %esp 5/r32/ebp
 8722     5d/pop-to-ebp
 8723     c3/return
 8724 
 8725 # format for variables with types
 8726 #   x: int
 8727 #   x: int,
 8728 #   x/eax: int
 8729 #   x/eax: int,
 8730 # ignores at most one trailing comma
 8731 # WARNING: modifies name
 8732 parse-var-with-type:  # name: (addr slice), first-line: (addr stream byte), out: (addr handle var), err: (addr buffered-file), ed: (addr exit-descriptor)
 8733     # pseudocode:
 8734     #   var s: slice
 8735     #   if (!slice-ends-with(name, ":"))
 8736     #     abort
 8737     #   --name->end to skip ':'
 8738     #   next-token-from-slice(name->start, name->end, '/', s)
 8739     #   new-var-from-slice(s, out)
 8740     #   ## register
 8741     #   next-token-from-slice(s->end, name->end, '/', s)
 8742     #   if (!slice-empty?(s))
 8743     #     out->register = slice-to-string(s)
 8744     #   ## type
 8745     #   var type: (handle type-tree) = parse-type(first-line)
 8746     #   out->type = type
 8747     #
 8748     # . prologue
 8749     55/push-ebp
 8750     89/<- %ebp 4/r32/esp
 8751     # . save registers
 8752     50/push-eax
 8753     51/push-ecx
 8754     52/push-edx
 8755     53/push-ebx
 8756     56/push-esi
 8757     57/push-edi
 8758     # esi = name
 8759     8b/-> *(ebp+8) 6/r32/esi
 8760     # if (!slice-ends-with?(name, ":")) abort
 8761     8b/-> *(esi+4) 1/r32/ecx  # Slice-end
 8762     49/decrement-ecx
 8763     8a/copy-byte *ecx 1/r32/CL
 8764     81 4/subop/and %ecx 0xff/imm32
 8765     81 7/subop/compare %ecx 0x3a/imm32/colon
 8766     0f 85/jump-if-!= $parse-var-with-type:abort/disp32
 8767     # --name->end to skip ':'
 8768     ff 1/subop/decrement *(esi+4)
 8769     # var s/ecx: slice
 8770     68/push 0/imm32/end
 8771     68/push 0/imm32/start
 8772     89/<- %ecx 4/r32/esp
 8773 $parse-var-with-type:parse-name:
 8774     (next-token-from-slice *esi *(esi+4) 0x2f %ecx)  # Slice-start, Slice-end, '/'
 8775 $parse-var-with-type:create-var:
 8776     # new-var-from-slice(s, out)
 8777     (new-var-from-slice Heap %ecx *(ebp+0x10))
 8778     # save out->register
 8779 $parse-var-with-type:save-register:
 8780     # . var out-addr/edi: (addr var) = lookup(*out)
 8781     8b/-> *(ebp+0x10) 7/r32/edi
 8782     (lookup *edi *(edi+4))  # => eax
 8783     89/<- %edi 0/r32/eax
 8784     # . s = next-token(...)
 8785     (next-token-from-slice *(ecx+4) *(esi+4) 0x2f %ecx)  # s->end, name->end, '/'
 8786     # . if (!slice-empty?(s)) out->register = slice-to-string(s)
 8787     {
 8788 $parse-var-with-type:write-register:
 8789       (slice-empty? %ecx)  # => eax
 8790       3d/compare-eax-and 0/imm32/false
 8791       75/jump-if-!= break/disp8
 8792       # out->register = slice-to-string(s)
 8793       8d/copy-address *(edi+0x18) 0/r32/eax  # Var-register
 8794       (slice-to-string Heap %ecx %eax)
 8795     }
 8796 $parse-var-with-type:save-type:
 8797     8d/copy-address *(edi+8) 0/r32/eax  # Var-type
 8798     (parse-type Heap *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 8799 $parse-var-with-type:end:
 8800     # . reclaim locals
 8801     81 0/subop/add %esp 8/imm32
 8802     # . restore registers
 8803     5f/pop-to-edi
 8804     5e/pop-to-esi
 8805     5b/pop-to-ebx
 8806     5a/pop-to-edx
 8807     59/pop-to-ecx
 8808     58/pop-to-eax
 8809     # . epilogue
 8810     89/<- %esp 5/r32/ebp
 8811     5d/pop-to-ebp
 8812     c3/return
 8813 
 8814 $parse-var-with-type:abort:
 8815     # error("var should have form 'name: type' in '" line "'\n")
 8816     (write-buffered *(ebp+0x14) "var should have form 'name: type' in '")
 8817     (flush *(ebp+0x14))
 8818     (rewind-stream *(ebp+0xc))
 8819     (write-stream-data *(ebp+0x14) *(ebp+0xc))
 8820     (write-buffered *(ebp+0x14) "'\n")
 8821     (flush *(ebp+0x14))
 8822     (stop *(ebp+0x18) 1)
 8823     # never gets here
 8824 
 8825 parse-type:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle type-tree), err: (addr buffered-file), ed: (addr exit-descriptor)
 8826     # pseudocode:
 8827     #   var s: slice = next-mu-token(in)
 8828     #   assert s != ""
 8829     #   assert s != "->"
 8830     #   assert s != "{"
 8831     #   assert s != "}"
 8832     #   if s == ")"
 8833     #     return
 8834     #   out = allocate(Type-tree)
 8835     #   if s != "("
 8836     #     HACK: if s is an int, parse and return it
 8837     #     out->is-atom? = true
 8838     #     if (s[0] == "_")
 8839     #       out->value = type-parameter
 8840     #       out->parameter-name = slice-to-string(ad, s)
 8841     #     else
 8842     #       out->value = pos-or-insert-slice(Type-id, s)
 8843     #     return
 8844     #   out->left = parse-type(ad, in)
 8845     #   out->right = parse-type-tree(ad, in)
 8846     #
 8847     # . prologue
 8848     55/push-ebp
 8849     89/<- %ebp 4/r32/esp
 8850     # . save registers
 8851     50/push-eax
 8852     51/push-ecx
 8853     52/push-edx
 8854     # clear out
 8855     (zero-out *(ebp+0x10) *Handle-size)
 8856     # var s/ecx: slice
 8857     68/push 0/imm32
 8858     68/push 0/imm32
 8859     89/<- %ecx 4/r32/esp
 8860     # s = next-mu-token(in)
 8861     (next-mu-token *(ebp+0xc) %ecx)
 8862 #?     (write-buffered Stderr "tok: ")
 8863 #?     (write-slice-buffered Stderr %ecx)
 8864 #?     (write-buffered Stderr "$\n")
 8865 #?     (flush Stderr)
 8866     # assert s != ""
 8867     (slice-equal? %ecx "")  # => eax
 8868     3d/compare-eax-and 0/imm32/false
 8869     0f 85/jump-if-!= $parse-type:abort/disp32
 8870     # assert s != "{"
 8871     (slice-equal? %ecx "{")  # => eax
 8872     3d/compare-eax-and 0/imm32/false
 8873     0f 85/jump-if-!= $parse-type:abort/disp32
 8874     # assert s != "}"
 8875     (slice-equal? %ecx "}")  # => eax
 8876     3d/compare-eax-and 0/imm32/false
 8877     0f 85/jump-if-!= $parse-type:abort/disp32
 8878     # assert s != "->"
 8879     (slice-equal? %ecx "->")  # => eax
 8880     3d/compare-eax-and 0/imm32/false
 8881     0f 85/jump-if-!= $parse-type:abort/disp32
 8882     # if (s == ")") return
 8883     (slice-equal? %ecx ")")  # => eax
 8884     3d/compare-eax-and 0/imm32/false
 8885     0f 85/jump-if-!= $parse-type:end/disp32
 8886     # out = new tree
 8887     (allocate *(ebp+8) *Type-tree-size *(ebp+0x10))
 8888     # var out-addr/edx: (addr type-tree) = lookup(*out)
 8889     8b/-> *(ebp+0x10) 2/r32/edx
 8890     (lookup *edx *(edx+4))  # => eax
 8891     89/<- %edx 0/r32/eax
 8892     {
 8893       # if (s != "(") break
 8894       (slice-equal? %ecx "(")  # => eax
 8895       3d/compare-eax-and 0/imm32/false
 8896       0f 85/jump-if-!= break/disp32
 8897       # if s is a number, store it in the type's size field
 8898       {
 8899 $parse-type:check-for-int:
 8900         # var tmp/eax: byte = *s->slice
 8901         8b/-> *ecx 0/r32/eax
 8902         8a/copy-byte *eax 0/r32/AL
 8903         81 4/subop/and %eax 0xff/imm32
 8904         # TODO: raise an error on `var x: (array int a)`
 8905         (is-decimal-digit? %eax)  # => eax
 8906         3d/compare-eax-and 0/imm32/false
 8907         74/jump-if-= break/disp8
 8908         #
 8909         (is-hex-int? %ecx)  # => eax
 8910         3d/compare-eax-and 0/imm32/false
 8911         74/jump-if-= break/disp8
 8912 $parse-type:int:
 8913         (check-mu-hex-int %ecx *(ebp+0x14) *(ebp+0x18))
 8914         (parse-hex-int-from-slice %ecx)  # => eax
 8915         c7 0/subop/copy *(edx+4) 9/imm32/type-id-array-capacity  # Type-tree-value
 8916         89/<- *(edx+8) 0/r32/eax  # Type-tree-value-size
 8917         e9/jump $parse-type:end/disp32
 8918       }
 8919 $parse-type:atom:
 8920       # out->is-atom? = true
 8921       c7 0/subop/copy *edx 1/imm32/true  # Type-tree-is-atom
 8922       {
 8923 $parse-type:check-for-type-parameter:
 8924         # var tmp/eax: byte = *s->slice
 8925         8b/-> *ecx 0/r32/eax
 8926         8a/copy-byte *eax 0/r32/AL
 8927         81 4/subop/and %eax 0xff/imm32
 8928         # if (tmp != '_') break
 8929         3d/compare-eax-and 0x5f/imm32/_
 8930         75/jump-if-!= break/disp8
 8931 $parse-type:type-parameter:
 8932         # out->value = type-parameter
 8933         c7 0/subop/copy *(edx+4) 0xa/imm32/type-parameter  # Type-tree-value
 8934         # out->parameter-name = slice-to-string(ad, s)
 8935         8d/copy-address *(edx+8) 0/r32/eax  # Type-tree-parameter-name
 8936         (slice-to-string *(ebp+8) %ecx %eax)
 8937         e9/jump $parse-type:end/disp32
 8938       }
 8939 $parse-type:non-type-parameter:
 8940       # out->value = pos-or-insert-slice(Type-id, s)
 8941       (pos-or-insert-slice Type-id %ecx)  # => eax
 8942       89/<- *(edx+4) 0/r32/eax  # Type-tree-value
 8943       e9/jump $parse-type:end/disp32
 8944     }
 8945 $parse-type:non-atom:
 8946     # otherwise s == "("
 8947     # out->left = parse-type(ad, in)
 8948     8d/copy-address *(edx+4) 0/r32/eax  # Type-tree-left
 8949     (parse-type *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 8950     # out->right = parse-type-tree(ad, in)
 8951     8d/copy-address *(edx+0xc) 0/r32/eax  # Type-tree-right
 8952     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 8953 $parse-type:end:
 8954     # . reclaim locals
 8955     81 0/subop/add %esp 8/imm32
 8956     # . restore registers
 8957     5a/pop-to-edx
 8958     59/pop-to-ecx
 8959     58/pop-to-eax
 8960     # . epilogue
 8961     89/<- %esp 5/r32/ebp
 8962     5d/pop-to-ebp
 8963     c3/return
 8964 
 8965 $parse-type:abort:
 8966     # error("unexpected token when parsing type: '" s "'\n")
 8967     (write-buffered *(ebp+0x14) "unexpected token when parsing type: '")
 8968     (write-slice-buffered *(ebp+0x14) %ecx)
 8969     (write-buffered *(ebp+0x14) "'\n")
 8970     (flush *(ebp+0x14))
 8971     (stop *(ebp+0x18) 1)
 8972     # never gets here
 8973 
 8974 parse-type-tree:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle type-tree), err: (addr buffered-file), ed: (addr exit-descriptor)
 8975     # pseudocode:
 8976     #   var tmp: (handle type-tree) = parse-type(ad, in)
 8977     #   if tmp == 0
 8978     #     return 0
 8979     #   out = allocate(Type-tree)
 8980     #   out->left = tmp
 8981     #   out->right = parse-type-tree(ad, in)
 8982     #
 8983     # . prologue
 8984     55/push-ebp
 8985     89/<- %ebp 4/r32/esp
 8986     # . save registers
 8987     50/push-eax
 8988     51/push-ecx
 8989     52/push-edx
 8990     #
 8991     (zero-out *(ebp+0x10) *Handle-size)
 8992     # var tmp/ecx: (handle type-tree)
 8993     68/push 0/imm32
 8994     68/push 0/imm32
 8995     89/<- %ecx 4/r32/esp
 8996     # tmp = parse-type(ad, in)
 8997     (parse-type *(ebp+8) *(ebp+0xc) %ecx *(ebp+0x14) *(ebp+0x18))
 8998     # if (tmp == 0) return
 8999     81 7/subop/compare *ecx 0/imm32
 9000     74/jump-if-= $parse-type-tree:end/disp8
 9001     # out = new tree
 9002     (allocate *(ebp+8) *Type-tree-size *(ebp+0x10))
 9003     # var out-addr/edx: (addr tree) = lookup(*out)
 9004     8b/-> *(ebp+0x10) 2/r32/edx
 9005     (lookup *edx *(edx+4))  # => eax
 9006     89/<- %edx 0/r32/eax
 9007     # out->left = tmp
 9008     8b/-> *ecx 0/r32/eax
 9009     89/<- *(edx+4) 0/r32/eax  # Type-tree-left
 9010     8b/-> *(ecx+4) 0/r32/eax
 9011     89/<- *(edx+8) 0/r32/eax  # Type-tree-left
 9012     # out->right = parse-type-tree(ad, in)
 9013     8d/copy-address *(edx+0xc) 0/r32/eax  # Type-tree-right
 9014     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 9015 $parse-type-tree:end:
 9016     # . reclaim locals
 9017     81 0/subop/add %esp 8/imm32
 9018     # . restore registers
 9019     5a/pop-to-edx
 9020     59/pop-to-ecx
 9021     58/pop-to-eax
 9022     # . epilogue
 9023     89/<- %esp 5/r32/ebp
 9024     5d/pop-to-ebp
 9025     c3/return
 9026 
 9027 next-mu-token:  # in: (addr stream byte), out: (addr slice)
 9028     # pseudocode:
 9029     # start:
 9030     #   skip-chars-matching-whitespace(in)
 9031     #   if in->read >= in->write              # end of in
 9032     #     out = {0, 0}
 9033     #     return
 9034     #   out->start = &in->data[in->read]
 9035     #   var curr-byte/eax: byte = in->data[in->read]
 9036     #   if curr->byte == ','                  # comment token
 9037     #     ++in->read
 9038     #     goto start
 9039     #   if curr-byte == '#'                   # comment
 9040     #     goto done                             # treat as eof
 9041     #   if curr-byte == '"'                   # string literal
 9042     #     skip-string(in)
 9043     #     goto done                           # no metadata
 9044     #   if curr-byte == '('
 9045     #     ++in->read
 9046     #     goto done
 9047     #   if curr-byte == ')'
 9048     #     ++in->read
 9049     #     goto done
 9050     #   # read a word
 9051     #   while true
 9052     #     if in->read >= in->write
 9053     #       break
 9054     #     curr-byte = in->data[in->read]
 9055     #     if curr-byte == ' '
 9056     #       break
 9057     #     if curr-byte == '\r'
 9058     #       break
 9059     #     if curr-byte == '\n'
 9060     #       break
 9061     #     if curr-byte == '('
 9062     #       break
 9063     #     if curr-byte == ')'
 9064     #       break
 9065     #     if curr-byte == ','
 9066     #       break
 9067     #     ++in->read
 9068     # done:
 9069     #   out->end = &in->data[in->read]
 9070     #
 9071     # . prologue
 9072     55/push-ebp
 9073     89/<- %ebp 4/r32/esp
 9074     # . save registers
 9075     50/push-eax
 9076     51/push-ecx
 9077     56/push-esi
 9078     57/push-edi
 9079     # esi = in
 9080     8b/-> *(ebp+8) 6/r32/esi
 9081     # edi = out
 9082     8b/-> *(ebp+0xc) 7/r32/edi
 9083 $next-mu-token:start:
 9084     (skip-chars-matching-whitespace %esi)
 9085 $next-mu-token:check0:
 9086     # if (in->read >= in->write) return out = {0, 0}
 9087     # . ecx = in->read
 9088     8b/-> *(esi+4) 1/r32/ecx
 9089     # . if (ecx >= in->write) return out = {0, 0}
 9090     3b/compare<- *esi 1/r32/ecx
 9091     c7 0/subop/copy *edi 0/imm32
 9092     c7 0/subop/copy *(edi+4) 0/imm32
 9093     0f 8d/jump-if->= $next-mu-token:end/disp32
 9094     # out->start = &in->data[in->read]
 9095     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
 9096     89/<- *edi 0/r32/eax
 9097     # var curr-byte/eax: byte = in->data[in->read]
 9098     31/xor-with %eax 0/r32/eax
 9099     8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
 9100     {
 9101 $next-mu-token:check-for-comma:
 9102       # if (curr-byte != ',') break
 9103       3d/compare-eax-and 0x2c/imm32/comma
 9104       75/jump-if-!= break/disp8
 9105       # ++in->read
 9106       ff 0/subop/increment *(esi+4)
 9107       # restart
 9108       e9/jump $next-mu-token:start/disp32
 9109     }
 9110     {
 9111 $next-mu-token:check-for-comment:
 9112       # if (curr-byte != '#') break
 9113       3d/compare-eax-and 0x23/imm32/pound
 9114       75/jump-if-!= break/disp8
 9115       # return eof
 9116       e9/jump $next-mu-token:done/disp32
 9117     }
 9118     {
 9119 $next-mu-token:check-for-string-literal:
 9120       # if (curr-byte != '"') break
 9121       3d/compare-eax-and 0x22/imm32/dquote
 9122       75/jump-if-!= break/disp8
 9123       (skip-string %esi)
 9124       # return
 9125       e9/jump $next-mu-token:done/disp32
 9126     }
 9127     {
 9128 $next-mu-token:check-for-open-paren:
 9129       # if (curr-byte != '(') break
 9130       3d/compare-eax-and 0x28/imm32/open-paren
 9131       75/jump-if-!= break/disp8
 9132       # ++in->read
 9133       ff 0/subop/increment *(esi+4)
 9134       # return
 9135       e9/jump $next-mu-token:done/disp32
 9136     }
 9137     {
 9138 $next-mu-token:check-for-close-paren:
 9139       # if (curr-byte != ')') break
 9140       3d/compare-eax-and 0x29/imm32/close-paren
 9141       75/jump-if-!= break/disp8
 9142       # ++in->read
 9143       ff 0/subop/increment *(esi+4)
 9144       # return
 9145       e9/jump $next-mu-token:done/disp32
 9146     }
 9147     {
 9148 $next-mu-token:regular-word-without-metadata:
 9149       # if (in->read >= in->write) break
 9150       # . ecx = in->read
 9151       8b/-> *(esi+4) 1/r32/ecx
 9152       # . if (ecx >= in->write) break
 9153       3b/compare<- *esi 1/r32/ecx
 9154       7d/jump-if->= break/disp8
 9155       # var c/eax: byte = in->data[in->read]
 9156       31/xor-with %eax 0/r32/eax
 9157       8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
 9158       # if (c == ' ') break
 9159       3d/compare-eax-and 0x20/imm32/space
 9160       74/jump-if-= break/disp8
 9161       # if (c == '\r') break
 9162       3d/compare-eax-and 0xd/imm32/carriage-return
 9163       74/jump-if-= break/disp8
 9164       # if (c == '\n') break
 9165       3d/compare-eax-and 0xa/imm32/newline
 9166       74/jump-if-= break/disp8
 9167       # if (c == '(') break
 9168       3d/compare-eax-and 0x28/imm32/open-paren
 9169       0f 84/jump-if-= break/disp32
 9170       # if (c == ')') break
 9171       3d/compare-eax-and 0x29/imm32/close-paren
 9172       0f 84/jump-if-= break/disp32
 9173       # if (c == ',') break
 9174       3d/compare-eax-and 0x2c/imm32/comma
 9175       0f 84/jump-if-= break/disp32
 9176       # ++in->read
 9177       ff 0/subop/increment *(esi+4)
 9178       #
 9179       e9/jump loop/disp32
 9180     }
 9181 $next-mu-token:done:
 9182     # out->end = &in->data[in->read]
 9183     8b/-> *(esi+4) 1/r32/ecx
 9184     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
 9185     89/<- *(edi+4) 0/r32/eax
 9186 $next-mu-token:end:
 9187     # . restore registers
 9188     5f/pop-to-edi
 9189     5e/pop-to-esi
 9190     59/pop-to-ecx
 9191     58/pop-to-eax
 9192     # . epilogue
 9193     89/<- %esp 5/r32/ebp
 9194     5d/pop-to-ebp
 9195     c3/return
 9196 
 9197 pos-or-insert-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
 9198     # . prologue
 9199     55/push-ebp
 9200     89/<- %ebp 4/r32/esp
 9201     # if (pos-slice(arr, s) != -1) return it
 9202     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
 9203     3d/compare-eax-and -1/imm32
 9204     75/jump-if-!= $pos-or-insert-slice:end/disp8
 9205 $pos-or-insert-slice:insert:
 9206     # var s2/eax: (handle array byte)
 9207     68/push 0/imm32
 9208     68/push 0/imm32
 9209     89/<- %eax 4/r32/esp
 9210     (slice-to-string Heap *(ebp+0xc) %eax)
 9211     # throw away alloc-id
 9212     (lookup *eax *(eax+4))  # => eax
 9213     (write-int *(ebp+8) %eax)
 9214     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
 9215 $pos-or-insert-slice:end:
 9216     # . reclaim locals
 9217     81 0/subop/add %esp 8/imm32
 9218     # . epilogue
 9219     89/<- %esp 5/r32/ebp
 9220     5d/pop-to-ebp
 9221     c3/return
 9222 
 9223 # return the index in an array of strings matching 's', -1 if not found
 9224 # index is denominated in elements, not bytes
 9225 pos-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
 9226     # . prologue
 9227     55/push-ebp
 9228     89/<- %ebp 4/r32/esp
 9229     # . save registers
 9230     51/push-ecx
 9231     52/push-edx
 9232     53/push-ebx
 9233     56/push-esi
 9234 #?     (write-buffered Stderr "pos-slice: ")
 9235 #?     (write-slice-buffered Stderr *(ebp+0xc))
 9236 #?     (write-buffered Stderr "\n")
 9237 #?     (flush Stderr)
 9238     # esi = arr
 9239     8b/-> *(ebp+8) 6/r32/esi
 9240     # var index/ecx: int = 0
 9241     b9/copy-to-ecx 0/imm32
 9242     # var curr/edx: (addr (addr array byte)) = arr->data
 9243     8d/copy-address *(esi+0xc) 2/r32/edx
 9244     # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write]
 9245     8b/-> *esi 3/r32/ebx
 9246     8d/copy-address *(esi+ebx+0xc) 3/r32/ebx
 9247     {
 9248 #?       (write-buffered Stderr "  ")
 9249 #?       (write-int32-hex-buffered Stderr %ecx)
 9250 #?       (write-buffered Stderr "\n")
 9251 #?       (flush Stderr)
 9252       # if (curr >= max) return -1
 9253       39/compare %edx 3/r32/ebx
 9254       b8/copy-to-eax -1/imm32
 9255       73/jump-if-addr>= $pos-slice:end/disp8
 9256       # if (slice-equal?(s, *curr)) break
 9257       (slice-equal? *(ebp+0xc) *edx)  # => eax
 9258       3d/compare-eax-and 0/imm32/false
 9259       75/jump-if-!= break/disp8
 9260       # ++index
 9261       41/increment-ecx
 9262       # curr += 4
 9263       81 0/subop/add %edx 4/imm32
 9264       #
 9265       eb/jump loop/disp8
 9266     }
 9267     # return index
 9268     89/<- %eax 1/r32/ecx
 9269 $pos-slice:end:
 9270 #?     (write-buffered Stderr "=> ")
 9271 #?     (write-int32-hex-buffered Stderr %eax)
 9272 #?     (write-buffered Stderr "\n")
 9273     # . restore registers
 9274     5e/pop-to-esi
 9275     5b/pop-to-ebx
 9276     5a/pop-to-edx
 9277     59/pop-to-ecx
 9278     # . epilogue
 9279     89/<- %esp 5/r32/ebp
 9280     5d/pop-to-ebp
 9281     c3/return
 9282 
 9283 test-parse-var-with-type:
 9284     # . prologue
 9285     55/push-ebp
 9286     89/<- %ebp 4/r32/esp
 9287     # setup
 9288     8b/-> *Primitive-type-ids 0/r32/eax
 9289     89/<- *Type-id 0/r32/eax  # stream-write
 9290     # (eax..ecx) = "x:"
 9291     b8/copy-to-eax "x:"/imm32
 9292     8b/-> *eax 1/r32/ecx
 9293     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9294     05/add-to-eax 4/imm32
 9295     # var slice/ecx: slice = {eax, ecx}
 9296     51/push-ecx
 9297     50/push-eax
 9298     89/<- %ecx 4/r32/esp
 9299     # _test-input-stream contains "int"
 9300     (clear-stream _test-input-stream)
 9301     (write _test-input-stream "int")
 9302     # var v/edx: (handle var)
 9303     68/push 0/imm32
 9304     68/push 0/imm32
 9305     89/<- %edx 4/r32/esp
 9306     #
 9307     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 9308     # var v-addr/edx: (addr var) = lookup(v)
 9309     (lookup *edx *(edx+4))  # => eax
 9310     89/<- %edx 0/r32/eax
 9311     # check v-addr->name
 9312     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 9313     (check-strings-equal %eax "x" "F - test-parse-var-with-type/name")
 9314     # check v-addr->type
 9315     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 9316     (check-ints-equal *eax 1 "F - test-parse-var-with-type/type:0")  # Type-tree-is-atom
 9317     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type/type:1")  # Type-tree-value
 9318     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type/type:2")  # Type-tree-right
 9319     # . epilogue
 9320     89/<- %esp 5/r32/ebp
 9321     5d/pop-to-ebp
 9322     c3/return
 9323 
 9324 test-parse-var-with-type-and-register:
 9325     # . prologue
 9326     55/push-ebp
 9327     89/<- %ebp 4/r32/esp
 9328     # setup
 9329     8b/-> *Primitive-type-ids 0/r32/eax
 9330     89/<- *Type-id 0/r32/eax  # stream-write
 9331     # (eax..ecx) = "x/eax:"
 9332     b8/copy-to-eax "x/eax:"/imm32
 9333     8b/-> *eax 1/r32/ecx
 9334     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9335     05/add-to-eax 4/imm32
 9336     # var slice/ecx: slice = {eax, ecx}
 9337     51/push-ecx
 9338     50/push-eax
 9339     89/<- %ecx 4/r32/esp
 9340     # _test-input-stream contains "int"
 9341     (clear-stream _test-input-stream)
 9342     (write _test-input-stream "int")
 9343     # var v/edx: (handle var)
 9344     68/push 0/imm32
 9345     68/push 0/imm32
 9346     89/<- %edx 4/r32/esp
 9347     #
 9348     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 9349     # var v-addr/edx: (addr var) = lookup(v)
 9350     (lookup *edx *(edx+4))  # => eax
 9351     89/<- %edx 0/r32/eax
 9352     # check v-addr->name
 9353     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 9354     (check-strings-equal %eax "x" "F - test-parse-var-with-type-and-register/name")
 9355     # check v-addr->register
 9356     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 9357     (check-strings-equal %eax "eax" "F - test-parse-var-with-type-and-register/register")
 9358     # check v-addr->type
 9359     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 9360     (check-ints-equal *eax 1 "F - test-parse-var-with-type-and-register/type:0")  # Type-tree-is-atom
 9361     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type-and-register/type:1")  # Type-tree-left
 9362     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type-and-register/type:2")  # Type-tree-right
 9363     # . epilogue
 9364     89/<- %esp 5/r32/ebp
 9365     5d/pop-to-ebp
 9366     c3/return
 9367 
 9368 test-parse-var-with-trailing-characters:
 9369     # . prologue
 9370     55/push-ebp
 9371     89/<- %ebp 4/r32/esp
 9372     # setup
 9373     8b/-> *Primitive-type-ids 0/r32/eax
 9374     89/<- *Type-id 0/r32/eax  # stream-write
 9375     # (eax..ecx) = "x:"
 9376     b8/copy-to-eax "x:"/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     # _test-input-stream contains "int,"
 9385     (clear-stream _test-input-stream)
 9386     (write _test-input-stream "int,")
 9387     # var v/edx: (handle var)
 9388     68/push 0/imm32
 9389     68/push 0/imm32
 9390     89/<- %edx 4/r32/esp
 9391     #
 9392     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 9393     # var v-addr/edx: (addr var) = lookup(v)
 9394     (lookup *edx *(edx+4))  # => eax
 9395     89/<- %edx 0/r32/eax
 9396     # check v-addr->name
 9397     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 9398     (check-strings-equal %eax "x" "F - test-parse-var-with-trailing-characters/name")
 9399     # check v-addr->register
 9400     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-trailing-characters/register")  # Var-register
 9401     # check v-addr->type
 9402     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 9403     (check-ints-equal *eax 1 "F - test-parse-var-with-trailing-characters/type:0")  # Type-tree-is-atom
 9404     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-trailing-characters/type:1")  # Type-tree-left
 9405     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-trailing-characters/type:1")  # Type-tree-right
 9406     # . epilogue
 9407     89/<- %esp 5/r32/ebp
 9408     5d/pop-to-ebp
 9409     c3/return
 9410 
 9411 test-parse-var-with-register-and-trailing-characters:
 9412     # . prologue
 9413     55/push-ebp
 9414     89/<- %ebp 4/r32/esp
 9415     # setup
 9416     8b/-> *Primitive-type-ids 0/r32/eax
 9417     89/<- *Type-id 0/r32/eax  # stream-write
 9418     # (eax..ecx) = "x/eax:"
 9419     b8/copy-to-eax "x/eax:"/imm32
 9420     8b/-> *eax 1/r32/ecx
 9421     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9422     05/add-to-eax 4/imm32
 9423     # var slice/ecx: slice = {eax, ecx}
 9424     51/push-ecx
 9425     50/push-eax
 9426     89/<- %ecx 4/r32/esp
 9427     # _test-input-stream contains "int,"
 9428     (clear-stream _test-input-stream)
 9429     (write _test-input-stream "int,")
 9430     # var v/edx: (handle var)
 9431     68/push 0/imm32
 9432     68/push 0/imm32
 9433     89/<- %edx 4/r32/esp
 9434     #
 9435     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 9436     # var v-addr/edx: (addr var) = lookup(v)
 9437     (lookup *edx *(edx+4))  # => eax
 9438     89/<- %edx 0/r32/eax
 9439     # check v-addr->name
 9440     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 9441     (check-strings-equal %eax "x" "F - test-parse-var-with-register-and-trailing-characters/name")
 9442     # check v-addr->register
 9443     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 9444     (check-strings-equal %eax "eax" "F - test-parse-var-with-register-and-trailing-characters/register")
 9445     # check v-addr->type
 9446     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 9447     (check-ints-equal *eax 1 "F - test-parse-var-with-register-and-trailing-characters/type:0")  # Type-tree-is-atom
 9448     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-register-and-trailing-characters/type:1")  # Type-tree-left
 9449     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-register-and-trailing-characters/type:2")  # Type-tree-right
 9450     # . epilogue
 9451     89/<- %esp 5/r32/ebp
 9452     5d/pop-to-ebp
 9453     c3/return
 9454 
 9455 test-parse-var-with-compound-type:
 9456     # . prologue
 9457     55/push-ebp
 9458     89/<- %ebp 4/r32/esp
 9459     # setup
 9460     8b/-> *Primitive-type-ids 0/r32/eax
 9461     89/<- *Type-id 0/r32/eax  # stream-write
 9462     # (eax..ecx) = "x:"
 9463     b8/copy-to-eax "x:"/imm32
 9464     8b/-> *eax 1/r32/ecx
 9465     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9466     05/add-to-eax 4/imm32
 9467     # var slice/ecx: slice = {eax, ecx}
 9468     51/push-ecx
 9469     50/push-eax
 9470     89/<- %ecx 4/r32/esp
 9471     # _test-input-stream contains "(addr int)"
 9472     (clear-stream _test-input-stream)
 9473     (write _test-input-stream "(addr int)")
 9474     # var v/edx: (handle var)
 9475     68/push 0/imm32
 9476     68/push 0/imm32
 9477     89/<- %edx 4/r32/esp
 9478     #
 9479     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 9480     # var v-addr/edx: (addr var) = lookup(v)
 9481     (lookup *edx *(edx+4))  # => eax
 9482     89/<- %edx 0/r32/eax
 9483     # check v-addr->name
 9484     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 9485     (check-strings-equal %eax "x" "F - test-parse-var-with-compound-type/name")
 9486     # check v-addr->register
 9487     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-compound-type/register")  # Var-register
 9488     # - check v-addr->type
 9489     # var type/edx: (addr type-tree) = var->type
 9490     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 9491     89/<- %edx 0/r32/eax
 9492     # type is a non-atom
 9493     (check-ints-equal *edx 0 "F - test-parse-var-with-compound-type/type:0")  # Type-tree-is-atom
 9494     # type->left == atom(addr)
 9495     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
 9496     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:1")  # Type-tree-is-atom
 9497     (check-ints-equal *(eax+4) 2 "F - test-parse-var-with-compound-type/type:2")  # Type-tree-value
 9498     # type->right->left == atom(int)
 9499     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
 9500     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
 9501     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:3")  # Type-tree-is-atom
 9502     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-compound-type/type:4")  # Type-tree-value
 9503     # type->right->right == null
 9504     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-compound-type/type:5")  # Type-tree-right
 9505     # . epilogue
 9506     89/<- %esp 5/r32/ebp
 9507     5d/pop-to-ebp
 9508     c3/return
 9509 
 9510 # identifier starts with a letter or '$' or '_'
 9511 # no constraints at the moment on later letters
 9512 # all we really want to do so far is exclude '{', '}' and '->'
 9513 is-identifier?:  # in: (addr slice) -> result/eax: boolean
 9514     # . prologue
 9515     55/push-ebp
 9516     89/<- %ebp 4/r32/esp
 9517     # if (slice-empty?(in)) return false
 9518     (slice-empty? *(ebp+8))  # => eax
 9519     3d/compare-eax-and 0/imm32/false
 9520     75/jump-if-!= $is-identifier?:false/disp8
 9521     # var c/eax: byte = *in->start
 9522     8b/-> *(ebp+8) 0/r32/eax
 9523     8b/-> *eax 0/r32/eax
 9524     8a/copy-byte *eax 0/r32/AL
 9525     81 4/subop/and %eax 0xff/imm32
 9526     # if (c == '$') return true
 9527     3d/compare-eax-and 0x24/imm32/$
 9528     74/jump-if-= $is-identifier?:true/disp8
 9529     # if (c == '_') return true
 9530     3d/compare-eax-and 0x5f/imm32/_
 9531     74/jump-if-= $is-identifier?:true/disp8
 9532     # drop case
 9533     25/and-eax-with 0x5f/imm32
 9534     # if (c < 'A') return false
 9535     3d/compare-eax-and 0x41/imm32/A
 9536     7c/jump-if-< $is-identifier?:false/disp8
 9537     # if (c > 'Z') return false
 9538     3d/compare-eax-and 0x5a/imm32/Z
 9539     7f/jump-if-> $is-identifier?:false/disp8
 9540     # otherwise return true
 9541 $is-identifier?:true:
 9542     b8/copy-to-eax 1/imm32/true
 9543     eb/jump $is-identifier?:end/disp8
 9544 $is-identifier?:false:
 9545     b8/copy-to-eax 0/imm32/false
 9546 $is-identifier?:end:
 9547     # . epilogue
 9548     89/<- %esp 5/r32/ebp
 9549     5d/pop-to-ebp
 9550     c3/return
 9551 
 9552 test-is-identifier-dollar:
 9553     # . prologue
 9554     55/push-ebp
 9555     89/<- %ebp 4/r32/esp
 9556     # (eax..ecx) = "$a"
 9557     b8/copy-to-eax "$a"/imm32
 9558     8b/-> *eax 1/r32/ecx
 9559     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9560     05/add-to-eax 4/imm32
 9561     # var slice/ecx: slice = {eax, ecx}
 9562     51/push-ecx
 9563     50/push-eax
 9564     89/<- %ecx 4/r32/esp
 9565     #
 9566     (is-identifier? %ecx)
 9567     (check-ints-equal %eax 1 "F - test-is-identifier-dollar")
 9568     # . epilogue
 9569     89/<- %esp 5/r32/ebp
 9570     5d/pop-to-ebp
 9571     c3/return
 9572 
 9573 test-is-identifier-underscore:
 9574     # . prologue
 9575     55/push-ebp
 9576     89/<- %ebp 4/r32/esp
 9577     # (eax..ecx) = "_a"
 9578     b8/copy-to-eax "_a"/imm32
 9579     8b/-> *eax 1/r32/ecx
 9580     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9581     05/add-to-eax 4/imm32
 9582     # var slice/ecx: slice = {eax, ecx}
 9583     51/push-ecx
 9584     50/push-eax
 9585     89/<- %ecx 4/r32/esp
 9586     #
 9587     (is-identifier? %ecx)
 9588     (check-ints-equal %eax 1 "F - test-is-identifier-underscore")
 9589     # . epilogue
 9590     89/<- %esp 5/r32/ebp
 9591     5d/pop-to-ebp
 9592     c3/return
 9593 
 9594 test-is-identifier-a:
 9595     # . prologue
 9596     55/push-ebp
 9597     89/<- %ebp 4/r32/esp
 9598     # (eax..ecx) = "a$"
 9599     b8/copy-to-eax "a$"/imm32
 9600     8b/-> *eax 1/r32/ecx
 9601     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9602     05/add-to-eax 4/imm32
 9603     # var slice/ecx: slice = {eax, ecx}
 9604     51/push-ecx
 9605     50/push-eax
 9606     89/<- %ecx 4/r32/esp
 9607     #
 9608     (is-identifier? %ecx)
 9609     (check-ints-equal %eax 1 "F - test-is-identifier-a")
 9610     # . epilogue
 9611     89/<- %esp 5/r32/ebp
 9612     5d/pop-to-ebp
 9613     c3/return
 9614 
 9615 test-is-identifier-z:
 9616     # . prologue
 9617     55/push-ebp
 9618     89/<- %ebp 4/r32/esp
 9619     # (eax..ecx) = "z$"
 9620     b8/copy-to-eax "z$"/imm32
 9621     8b/-> *eax 1/r32/ecx
 9622     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9623     05/add-to-eax 4/imm32
 9624     # var slice/ecx: slice = {eax, ecx}
 9625     51/push-ecx
 9626     50/push-eax
 9627     89/<- %ecx 4/r32/esp
 9628     #
 9629     (is-identifier? %ecx)
 9630     (check-ints-equal %eax 1 "F - test-is-identifier-z")
 9631     # . epilogue
 9632     89/<- %esp 5/r32/ebp
 9633     5d/pop-to-ebp
 9634     c3/return
 9635 
 9636 test-is-identifier-A:
 9637     # . prologue
 9638     55/push-ebp
 9639     89/<- %ebp 4/r32/esp
 9640     # (eax..ecx) = "A$"
 9641     b8/copy-to-eax "A$"/imm32
 9642     8b/-> *eax 1/r32/ecx
 9643     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9644     05/add-to-eax 4/imm32
 9645     # var slice/ecx: slice = {eax, ecx}
 9646     51/push-ecx
 9647     50/push-eax
 9648     89/<- %ecx 4/r32/esp
 9649     #
 9650     (is-identifier? %ecx)
 9651     (check-ints-equal %eax 1 "F - test-is-identifier-A")
 9652     # . epilogue
 9653     89/<- %esp 5/r32/ebp
 9654     5d/pop-to-ebp
 9655     c3/return
 9656 
 9657 test-is-identifier-Z:
 9658     # . prologue
 9659     55/push-ebp
 9660     89/<- %ebp 4/r32/esp
 9661     # (eax..ecx) = "Z$"
 9662     b8/copy-to-eax "Z$"/imm32
 9663     8b/-> *eax 1/r32/ecx
 9664     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9665     05/add-to-eax 4/imm32
 9666     # var slice/ecx: slice = {eax, ecx}
 9667     51/push-ecx
 9668     50/push-eax
 9669     89/<- %ecx 4/r32/esp
 9670     #
 9671     (is-identifier? %ecx)
 9672     (check-ints-equal %eax 1 "F - test-is-identifier-Z")
 9673     # . epilogue
 9674     89/<- %esp 5/r32/ebp
 9675     5d/pop-to-ebp
 9676     c3/return
 9677 
 9678 test-is-identifier-at:
 9679     # character before 'A' is invalid
 9680     # . prologue
 9681     55/push-ebp
 9682     89/<- %ebp 4/r32/esp
 9683     # (eax..ecx) = "@a"
 9684     b8/copy-to-eax "@a"/imm32
 9685     8b/-> *eax 1/r32/ecx
 9686     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9687     05/add-to-eax 4/imm32
 9688     # var slice/ecx: slice = {eax, ecx}
 9689     51/push-ecx
 9690     50/push-eax
 9691     89/<- %ecx 4/r32/esp
 9692     #
 9693     (is-identifier? %ecx)
 9694     (check-ints-equal %eax 0 "F - test-is-identifier-@")
 9695     # . epilogue
 9696     89/<- %esp 5/r32/ebp
 9697     5d/pop-to-ebp
 9698     c3/return
 9699 
 9700 test-is-identifier-square-bracket:
 9701     # character after 'Z' is invalid
 9702     # . prologue
 9703     55/push-ebp
 9704     89/<- %ebp 4/r32/esp
 9705     # (eax..ecx) = "[a"
 9706     b8/copy-to-eax "[a"/imm32
 9707     8b/-> *eax 1/r32/ecx
 9708     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9709     05/add-to-eax 4/imm32
 9710     # var slice/ecx: slice = {eax, ecx}
 9711     51/push-ecx
 9712     50/push-eax
 9713     89/<- %ecx 4/r32/esp
 9714     #
 9715     (is-identifier? %ecx)
 9716     (check-ints-equal %eax 0 "F - test-is-identifier-@")
 9717     # . epilogue
 9718     89/<- %esp 5/r32/ebp
 9719     5d/pop-to-ebp
 9720     c3/return
 9721 
 9722 test-is-identifier-backtick:
 9723     # character before 'a' is invalid
 9724     # . prologue
 9725     55/push-ebp
 9726     89/<- %ebp 4/r32/esp
 9727     # (eax..ecx) = "`a"
 9728     b8/copy-to-eax "`a"/imm32
 9729     8b/-> *eax 1/r32/ecx
 9730     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9731     05/add-to-eax 4/imm32
 9732     # var slice/ecx: slice = {eax, ecx}
 9733     51/push-ecx
 9734     50/push-eax
 9735     89/<- %ecx 4/r32/esp
 9736     #
 9737     (is-identifier? %ecx)
 9738     (check-ints-equal %eax 0 "F - test-is-identifier-backtick")
 9739     # . epilogue
 9740     89/<- %esp 5/r32/ebp
 9741     5d/pop-to-ebp
 9742     c3/return
 9743 
 9744 test-is-identifier-curly-brace-open:
 9745     # character after 'z' is invalid; also used for blocks
 9746     # . prologue
 9747     55/push-ebp
 9748     89/<- %ebp 4/r32/esp
 9749     # (eax..ecx) = "{a"
 9750     b8/copy-to-eax "{a"/imm32
 9751     8b/-> *eax 1/r32/ecx
 9752     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9753     05/add-to-eax 4/imm32
 9754     # var slice/ecx: slice = {eax, ecx}
 9755     51/push-ecx
 9756     50/push-eax
 9757     89/<- %ecx 4/r32/esp
 9758     #
 9759     (is-identifier? %ecx)
 9760     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open")
 9761     # . epilogue
 9762     89/<- %esp 5/r32/ebp
 9763     5d/pop-to-ebp
 9764     c3/return
 9765 
 9766 test-is-identifier-curly-brace-close:
 9767     # . prologue
 9768     55/push-ebp
 9769     89/<- %ebp 4/r32/esp
 9770     # (eax..ecx) = "}a"
 9771     b8/copy-to-eax "}a"/imm32
 9772     8b/-> *eax 1/r32/ecx
 9773     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9774     05/add-to-eax 4/imm32
 9775     # var slice/ecx: slice = {eax, ecx}
 9776     51/push-ecx
 9777     50/push-eax
 9778     89/<- %ecx 4/r32/esp
 9779     #
 9780     (is-identifier? %ecx)
 9781     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close")
 9782     # . epilogue
 9783     89/<- %esp 5/r32/ebp
 9784     5d/pop-to-ebp
 9785     c3/return
 9786 
 9787 test-is-identifier-hyphen:
 9788     # disallow leading '-' since '->' has special meaning
 9789     # . prologue
 9790     55/push-ebp
 9791     89/<- %ebp 4/r32/esp
 9792     # (eax..ecx) = "-a"
 9793     b8/copy-to-eax "-a"/imm32
 9794     8b/-> *eax 1/r32/ecx
 9795     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9796     05/add-to-eax 4/imm32
 9797     # var slice/ecx: slice = {eax, ecx}
 9798     51/push-ecx
 9799     50/push-eax
 9800     89/<- %ecx 4/r32/esp
 9801     #
 9802     (is-identifier? %ecx)
 9803     (check-ints-equal %eax 0 "F - test-is-identifier-hyphen")
 9804     # . epilogue
 9805     89/<- %esp 5/r32/ebp
 9806     5d/pop-to-ebp
 9807     c3/return
 9808 
 9809 populate-mu-function-body:  # in: (addr buffered-file), out: (addr function), vars: (addr stack live-var), err: (addr buffered-file), ed: (addr exit-descriptor)
 9810     # . prologue
 9811     55/push-ebp
 9812     89/<- %ebp 4/r32/esp
 9813     # . save registers
 9814     50/push-eax
 9815     56/push-esi
 9816     57/push-edi
 9817     # esi = in
 9818     8b/-> *(ebp+8) 6/r32/esi
 9819     # edi = out
 9820     8b/-> *(ebp+0xc) 7/r32/edi
 9821     # initialize some global state
 9822     c7 0/subop/copy *Curr-block-depth 1/imm32
 9823     # parse-mu-block(in, vars, out, out->body)
 9824     8d/copy-address *(edi+0x18) 0/r32/eax  # Function-body
 9825     (parse-mu-block %esi *(ebp+0x10) %edi %eax *(ebp+0x14) *(ebp+0x18))
 9826 $populate-mu-function-body:end:
 9827     # . restore registers
 9828     5f/pop-to-edi
 9829     5e/pop-to-esi
 9830     58/pop-to-eax
 9831     # . epilogue
 9832     89/<- %esp 5/r32/ebp
 9833     5d/pop-to-ebp
 9834     c3/return
 9835 
 9836 # parses a block, assuming that the leading '{' has already been read by the caller
 9837 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)
 9838     # pseudocode:
 9839     #   var line: (stream byte 512)
 9840     #   var word-slice: slice
 9841     #   allocate(Heap, Stmt-size, out)
 9842     #   var out-addr: (addr block) = lookup(*out)
 9843     #   out-addr->tag = 0/block
 9844     #   out-addr->var = some unique name
 9845     #   push(vars, {out-addr->var, false})
 9846     #   while true                                  # line loop
 9847     #     clear-stream(line)
 9848     #     read-line-buffered(in, line)
 9849     #     if (line->write == 0) break               # end of file
 9850     #     word-slice = next-mu-token(line)
 9851     #     if slice-empty?(word-slice)               # end of line
 9852     #       continue
 9853     #     else if slice-starts-with?(word-slice, "#")
 9854     #       continue
 9855     #     else if slice-equal?(word-slice, "{")
 9856     #       assert(no-tokens-in(line))
 9857     #       block = parse-mu-block(in, vars, fn)
 9858     #       append-to-block(out-addr, block)
 9859     #     else if slice-equal?(word-slice, "}")
 9860     #       break
 9861     #     else if slice-ends-with?(word-slice, ":")
 9862     #       # TODO: error-check the rest of 'line'
 9863     #       --word-slice->end to skip ':'
 9864     #       named-block = parse-mu-named-block(word-slice, in, vars, fn)
 9865     #       append-to-block(out-addr, named-block)
 9866     #     else if slice-equal?(word-slice, "var")
 9867     #       var-def = parse-mu-var-def(line, vars, fn)
 9868     #       append-to-block(out-addr, var-def)
 9869     #     else
 9870     #       stmt = parse-mu-stmt(line, vars, fn)
 9871     #       append-to-block(out-addr, stmt)
 9872     #   pop(vars)
 9873     #
 9874     # . prologue
 9875     55/push-ebp
 9876     89/<- %ebp 4/r32/esp
 9877     # . save registers
 9878     50/push-eax
 9879     51/push-ecx
 9880     52/push-edx
 9881     53/push-ebx
 9882     57/push-edi
 9883     # var line/ecx: (stream byte 512)
 9884     81 5/subop/subtract %esp 0x200/imm32
 9885     68/push 0x200/imm32/size
 9886     68/push 0/imm32/read
 9887     68/push 0/imm32/write
 9888     89/<- %ecx 4/r32/esp
 9889     # var word-slice/edx: slice
 9890     68/push 0/imm32/end
 9891     68/push 0/imm32/start
 9892     89/<- %edx 4/r32/esp
 9893     # allocate into out
 9894     (allocate Heap *Stmt-size *(ebp+0x14))
 9895     # var out-addr/edi: (addr block) = lookup(*out)
 9896     8b/-> *(ebp+0x14) 7/r32/edi
 9897     (lookup *edi *(edi+4))  # => eax
 9898     89/<- %edi 0/r32/eax
 9899     # out-addr->tag is 0 (block) by default
 9900     # set out-addr->var
 9901     8d/copy-address *(edi+0xc) 0/r32/eax  # Block-var
 9902     (new-block-name *(ebp+0x10) %eax)
 9903     # push(vars, out-addr->var)
 9904     (push *(ebp+0xc) *(edi+0xc))  # Block-var
 9905     (push *(ebp+0xc) *(edi+0x10))  # Block-var
 9906     (push *(ebp+0xc) 0)  # false
 9907     # increment *Curr-block-depth
 9908     ff 0/subop/increment *Curr-block-depth
 9909     {
 9910 $parse-mu-block:line-loop:
 9911       # line = read-line-buffered(in)
 9912       (clear-stream %ecx)
 9913       (read-line-buffered *(ebp+8) %ecx)
 9914 #?       (write-buffered Stderr "line: ")
 9915 #?       (write-stream-data Stderr %ecx)
 9916 #? #?       (write-buffered Stderr Newline)  # line has its own newline
 9917 #?       (flush Stderr)
 9918 #?       (rewind-stream %ecx)
 9919       # if (line->write == 0) break
 9920       81 7/subop/compare *ecx 0/imm32
 9921       0f 84/jump-if-= break/disp32
 9922 #?       (write-buffered Stderr "vars:\n")
 9923 #?       (dump-vars *(ebp+0xc))
 9924       # word-slice = next-mu-token(line)
 9925       (next-mu-token %ecx %edx)
 9926 #?       (write-buffered Stderr "word: ")
 9927 #?       (write-slice-buffered Stderr %edx)
 9928 #?       (write-buffered Stderr Newline)
 9929 #?       (flush Stderr)
 9930       # if slice-empty?(word-slice) continue
 9931       (slice-empty? %edx)
 9932       3d/compare-eax-and 0/imm32/false
 9933       0f 85/jump-if-!= loop/disp32
 9934       # if (slice-starts-with?(word-slice, '#') continue
 9935       # . eax = *word-slice->start
 9936       8b/-> *edx 0/r32/eax
 9937       8a/copy-byte *eax 0/r32/AL
 9938       81 4/subop/and %eax 0xff/imm32
 9939       # . if (eax == '#') continue
 9940       3d/compare-eax-and 0x23/imm32/hash
 9941       0f 84/jump-if-= loop/disp32
 9942       # if slice-equal?(word-slice, "{")
 9943       {
 9944 $parse-mu-block:check-for-block:
 9945         (slice-equal? %edx "{")
 9946         3d/compare-eax-and 0/imm32/false
 9947         74/jump-if-= break/disp8
 9948         (check-no-tokens-left %ecx)
 9949         # parse new block and append
 9950         # . var tmp/eax: (handle block)
 9951         68/push 0/imm32
 9952         68/push 0/imm32
 9953         89/<- %eax 4/r32/esp
 9954         # .
 9955         (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 9956         (append-to-block Heap %edi  *eax *(eax+4))
 9957         # . reclaim tmp
 9958         81 0/subop/add %esp 8/imm32
 9959         # .
 9960         e9/jump $parse-mu-block:line-loop/disp32
 9961       }
 9962       # if slice-equal?(word-slice, "}") break
 9963 $parse-mu-block:check-for-end:
 9964       (slice-equal? %edx "}")
 9965       3d/compare-eax-and 0/imm32/false
 9966       0f 85/jump-if-!= break/disp32
 9967       # if slice-ends-with?(word-slice, ":") parse named block and append
 9968       {
 9969 $parse-mu-block:check-for-named-block:
 9970         # . eax = *(word-slice->end-1)
 9971         8b/-> *(edx+4) 0/r32/eax
 9972         48/decrement-eax
 9973         8a/copy-byte *eax 0/r32/AL
 9974         81 4/subop/and %eax 0xff/imm32
 9975         # . if (eax != ':') break
 9976         3d/compare-eax-and 0x3a/imm32/colon
 9977         0f 85/jump-if-!= break/disp32
 9978         # TODO: error-check the rest of 'line'
 9979         #
 9980         # skip ':'
 9981         ff 1/subop/decrement *(edx+4)  # Slice-end
 9982         # var tmp/eax: (handle block)
 9983         68/push 0/imm32
 9984         68/push 0/imm32
 9985         89/<- %eax 4/r32/esp
 9986         #
 9987         (parse-mu-named-block %edx *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 9988         (append-to-block Heap %edi  *eax *(eax+4))
 9989         # reclaim tmp
 9990         81 0/subop/add %esp 8/imm32
 9991         #
 9992         e9/jump $parse-mu-block:line-loop/disp32
 9993       }
 9994       # if slice-equal?(word-slice, "var")
 9995       {
 9996 $parse-mu-block:check-for-var:
 9997         (slice-equal? %edx "var")
 9998         3d/compare-eax-and 0/imm32/false
 9999         74/jump-if-= break/disp8
10000         # var tmp/eax: (handle block)
10001         68/push 0/imm32
10002         68/push 0/imm32
10003         89/<- %eax 4/r32/esp
10004         #
10005         (parse-mu-var-def %ecx *(ebp+0xc) %eax *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
10006         (append-to-block Heap %edi  *eax *(eax+4))
10007         # reclaim tmp
10008         81 0/subop/add %esp 8/imm32
10009         #
10010         e9/jump $parse-mu-block:line-loop/disp32
10011       }
10012 $parse-mu-block:regular-stmt:
10013       # otherwise
10014       # var tmp/eax: (handle block)
10015       68/push 0/imm32
10016       68/push 0/imm32
10017       89/<- %eax 4/r32/esp
10018       #
10019       (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
10020       (append-to-block Heap %edi  *eax *(eax+4))
10021       # reclaim tmp
10022       81 0/subop/add %esp 8/imm32
10023       #
10024       e9/jump loop/disp32
10025     } # end line loop
10026     (clean-up-blocks *(ebp+0xc) *Curr-block-depth *(ebp+0x10))
10027     # decrement *Curr-block-depth
10028     ff 1/subop/decrement *Curr-block-depth
10029     # pop(vars)
10030     (pop *(ebp+0xc))  # => eax
10031     (pop *(ebp+0xc))  # => eax
10032     (pop *(ebp+0xc))  # => eax
10033 $parse-mu-block:end:
10034     # . reclaim locals
10035     81 0/subop/add %esp 0x214/imm32
10036     # . restore registers
10037     5f/pop-to-edi
10038     5b/pop-to-ebx
10039     5a/pop-to-edx
10040     59/pop-to-ecx
10041     58/pop-to-eax
10042     # . epilogue
10043     89/<- %esp 5/r32/ebp
10044     5d/pop-to-ebp
10045     c3/return
10046 
10047 $parse-mu-block:abort:
10048     # error("'{' or '}' should be on its own line, but got '")
10049     (write-buffered *(ebp+0x18) "'{' or '}' should be on its own line, but got '")
10050     (rewind-stream %ecx)
10051     (write-stream-data *(ebp+0x18) %ecx)
10052     (write-buffered *(ebp+0x18) "'\n")
10053     (flush *(ebp+0x18))
10054     (stop *(ebp+0x1c) 1)
10055     # never gets here
10056 
10057 new-block-name:  # fn: (addr function), out: (addr handle var)
10058     # . prologue
10059     55/push-ebp
10060     89/<- %ebp 4/r32/esp
10061     # . save registers
10062     50/push-eax
10063     51/push-ecx
10064     52/push-edx
10065     # var n/ecx: int = len(fn->name) + 10 for an int + 2 for '$:'
10066     8b/-> *(ebp+8) 0/r32/eax
10067     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10068     8b/-> *eax 0/r32/eax  # String-size
10069     05/add-to-eax 0xd/imm32  # 10 + 2 for '$:'
10070     89/<- %ecx 0/r32/eax
10071     # var name/edx: (stream byte n)
10072     29/subtract-from %esp 1/r32/ecx
10073     ff 6/subop/push %ecx
10074     68/push 0/imm32/read
10075     68/push 0/imm32/write
10076     89/<- %edx 4/r32/esp
10077     (clear-stream %edx)
10078     # eax = fn->name
10079     8b/-> *(ebp+8) 0/r32/eax
10080     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10081     # construct result using Next-block-index (and increment it)
10082     (write %edx "$")
10083     (write %edx %eax)
10084     (write %edx ":")
10085     (write-int32-hex %edx *Next-block-index)
10086     ff 0/subop/increment *Next-block-index
10087     # var s/eax: slice = {name->data, name->data + name->write}  (clobbering edx)
10088     # . eax = name->write
10089     8b/-> *edx 0/r32/eax
10090     # . edx = name->data
10091     8d/copy-address *(edx+0xc) 2/r32/edx
10092     # . eax = name->write + name->data
10093     01/add-to %eax 2/r32/edx
10094     # . push {edx, eax}
10095     ff 6/subop/push %eax
10096     ff 6/subop/push %edx
10097     89/<- %eax 4/r32/esp
10098     # out = new literal(s)
10099     (new-literal Heap %eax *(ebp+0xc))
10100 #?     8b/-> *(ebp+0xc) 0/r32/eax
10101 #?     (write-buffered Stderr "type allocid in caller after new-literal: ")
10102 #?     (write-int32-hex-buffered Stderr *(eax+8))
10103 #?     (write-buffered Stderr " for var ")
10104 #?     (write-int32-hex-buffered Stderr %eax)
10105 #?     (write-buffered Stderr Newline)
10106 #?     (flush Stderr)
10107 $new-block-name:end:
10108     # . reclaim locals
10109     81 0/subop/add %ecx 0xc/imm32  # name.{read/write/len}
10110     81 0/subop/add %ecx 8/imm32  # slice
10111     01/add-to %esp 1/r32/ecx
10112     # . restore registers
10113     5a/pop-to-edx
10114     59/pop-to-ecx
10115     58/pop-to-eax
10116     # . epilogue
10117     89/<- %esp 5/r32/ebp
10118     5d/pop-to-ebp
10119     c3/return
10120 
10121 check-no-tokens-left:  # line: (addr stream byte)
10122     # . prologue
10123     55/push-ebp
10124     89/<- %ebp 4/r32/esp
10125     # . save registers
10126     50/push-eax
10127     51/push-ecx
10128     # var s/ecx: slice
10129     68/push 0/imm32/end
10130     68/push 0/imm32/start
10131     89/<- %ecx 4/r32/esp
10132     #
10133     (next-mu-token *(ebp+8) %ecx)
10134     # if slice-empty?(s) return
10135     (slice-empty? %ecx)
10136     3d/compare-eax-and 0/imm32/false
10137     75/jump-if-!= $check-no-tokens-left:end/disp8
10138     # if (slice-starts-with?(s, '#') return
10139     # . eax = *s->start
10140     8b/-> *edx 0/r32/eax
10141     8a/copy-byte *eax 0/r32/AL
10142     81 4/subop/and %eax 0xff/imm32
10143     # . if (eax == '#') continue
10144     3d/compare-eax-and 0x23/imm32/hash
10145     74/jump-if-= $check-no-tokens-left:end/disp8
10146     # abort
10147     (write-buffered Stderr "'{' or '}' should be on its own line, but got '")
10148     (rewind-stream %ecx)
10149     (write-stream 2 %ecx)
10150     (write-buffered Stderr "'\n")
10151     (flush Stderr)
10152     # . syscall(exit, 1)
10153     bb/copy-to-ebx  1/imm32
10154     e8/call syscall_exit/disp32
10155     # never gets here
10156 $check-no-tokens-left:end:
10157     # . reclaim locals
10158     81 0/subop/add %esp 8/imm32
10159     # . restore registers
10160     59/pop-to-ecx
10161     58/pop-to-eax
10162     # . epilogue
10163     89/<- %esp 5/r32/ebp
10164     5d/pop-to-ebp
10165     c3/return
10166 
10167 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)
10168     # pseudocode:
10169     #   var v: (handle var)
10170     #   new-literal(name, v)
10171     #   push(vars, {v, false})
10172     #   parse-mu-block(in, vars, fn, out)
10173     #   pop(vars)
10174     #   out->tag = block
10175     #   out->var = v
10176     #
10177     # . prologue
10178     55/push-ebp
10179     89/<- %ebp 4/r32/esp
10180     # . save registers
10181     50/push-eax
10182     51/push-ecx
10183     57/push-edi
10184     # var v/ecx: (handle var)
10185     68/push 0/imm32
10186     68/push 0/imm32
10187     89/<- %ecx 4/r32/esp
10188     #
10189     (new-literal Heap *(ebp+8) %ecx)
10190     # push(vars, v)
10191     (push *(ebp+0x10) *ecx)
10192     (push *(ebp+0x10) *(ecx+4))
10193     (push *(ebp+0x10) 0)  # false
10194     #
10195     (parse-mu-block *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20))
10196     # pop v off vars
10197     (pop *(ebp+0x10))  # => eax
10198     (pop *(ebp+0x10))  # => eax
10199     (pop *(ebp+0x10))  # => eax
10200     # var out-addr/edi: (addr stmt) = lookup(*out)
10201     8b/-> *(ebp+0x18) 7/r32/edi
10202     (lookup *edi *(edi+4))  # => eax
10203     89/<- %edi 0/r32/eax
10204     # out-addr->tag = named-block
10205     c7 0/subop/copy *edi 0/imm32/block  # Stmt-tag
10206     # out-addr->var = v
10207     8b/-> *ecx 0/r32/eax
10208     89/<- *(edi+0xc) 0/r32/eax  # Block-var
10209     8b/-> *(ecx+4) 0/r32/eax
10210     89/<- *(edi+0x10) 0/r32/eax  # Block-var
10211 $parse-mu-named-block:end:
10212     # . reclaim locals
10213     81 0/subop/add %esp 8/imm32
10214     # . restore registers
10215     5f/pop-to-edi
10216     59/pop-to-ecx
10217     58/pop-to-eax
10218     # . epilogue
10219     89/<- %esp 5/r32/ebp
10220     5d/pop-to-ebp
10221     c3/return
10222 
10223 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)
10224     # . prologue
10225     55/push-ebp
10226     89/<- %ebp 4/r32/esp
10227     # . save registers
10228     50/push-eax
10229     51/push-ecx
10230     52/push-edx
10231     53/push-ebx
10232     57/push-edi
10233     # edi = out
10234     8b/-> *(ebp+0x10) 7/r32/edi
10235     # var word-slice/ecx: slice
10236     68/push 0/imm32/end
10237     68/push 0/imm32/start
10238     89/<- %ecx 4/r32/esp
10239     # var v/edx: (handle var)
10240     68/push 0/imm32
10241     68/push 0/imm32
10242     89/<- %edx 4/r32/esp
10243     # v = parse-var-with-type(next-mu-token(line))
10244     (next-mu-token *(ebp+8) %ecx)
10245     (parse-var-with-type %ecx *(ebp+8) %edx *(ebp+0x18) *(ebp+0x1c))
10246     # var v-addr/eax: (addr var)
10247     (lookup *edx *(edx+4))  # => eax
10248     # v->block-depth = *Curr-block-depth
10249     8b/-> *Curr-block-depth 3/r32/ebx
10250     89/<- *(eax+0x10) 3/r32/ebx  # Var-block-depth
10251     # either v has no register and there's no more to this line
10252     8b/-> *(eax+0x18) 0/r32/eax  # Var-register
10253     3d/compare-eax-and 0/imm32
10254     {
10255       75/jump-if-!= break/disp8
10256       # TODO: disallow vars of type 'byte' on the stack
10257       # ensure that there's nothing else on this line
10258       (next-mu-token *(ebp+8) %ecx)
10259       (slice-empty? %ecx)  # => eax
10260       3d/compare-eax-and 0/imm32/false
10261       0f 84/jump-if-= $parse-mu-var-def:error2/disp32
10262       #
10263       (new-var-def Heap  *edx *(edx+4)  %edi)
10264       e9/jump $parse-mu-var-def:update-vars/disp32
10265     }
10266     # or v has a register and there's more to this line
10267     {
10268       0f 84/jump-if-= break/disp32
10269       # TODO: disallow vars of type 'byte' in registers 'esi' or 'edi'
10270       # TODO: vars of type 'byte' should only be initialized by clearing to 0
10271       # ensure that the next word is '<-'
10272       (next-mu-token *(ebp+8) %ecx)
10273       (slice-equal? %ecx "<-")  # => eax
10274       3d/compare-eax-and 0/imm32/false
10275       0f 84/jump-if-= $parse-mu-var-def:error1/disp32
10276       #
10277       (new-reg-var-def Heap  *edx *(edx+4)  %edi)
10278       (lookup *edi *(edi+4))  # => eax
10279       (add-operation-and-inputs-to-stmt %eax *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
10280     }
10281 $parse-mu-var-def:update-vars:
10282     # push 'v' at end of function
10283     (push *(ebp+0xc) *edx)
10284     (push *(ebp+0xc) *(edx+4))
10285     (push *(ebp+0xc) 0)  # Live-var-register-spilled is unused during parsing
10286 $parse-mu-var-def:end:
10287     # . reclaim locals
10288     81 0/subop/add %esp 0x10/imm32
10289     # . restore registers
10290     5f/pop-to-edi
10291     5b/pop-to-ebx
10292     5a/pop-to-edx
10293     59/pop-to-ecx
10294     58/pop-to-eax
10295     # . epilogue
10296     89/<- %esp 5/r32/ebp
10297     5d/pop-to-ebp
10298     c3/return
10299 
10300 $parse-mu-var-def:error1:
10301     (rewind-stream *(ebp+8))
10302     # error("register variable requires a valid instruction to initialize but got '" line "'\n")
10303     (write-buffered *(ebp+0x18) "register variable requires a valid instruction to initialize but got '")
10304     (flush *(ebp+0x18))
10305     (write-stream-data *(ebp+0x18) *(ebp+8))
10306     (write-buffered *(ebp+0x18) "'\n")
10307     (flush *(ebp+0x18))
10308     (stop *(ebp+0x1c) 1)
10309     # never gets here
10310 
10311 $parse-mu-var-def:error2:
10312     (rewind-stream *(ebp+8))
10313     # error("fn " fn ": var " var ": variables on the stack can't take an initializer\n")
10314     (write-buffered *(ebp+0x18) "fn ")
10315     8b/-> *(ebp+0x14) 0/r32/eax
10316     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10317     (write-buffered *(ebp+0x18) %eax)
10318     (write-buffered *(ebp+0x18) ": var ")
10319     # var v-addr/eax: (addr var) = lookup(v)
10320     (lookup *edx *(edx+4))  # => eax
10321     (lookup *eax *(eax+4))  # Var-name Var-name => eax
10322     (write-buffered *(ebp+0x18) %eax)
10323     (write-buffered *(ebp+0x18) ": variables on the stack can't take an initializer\n")
10324     (flush *(ebp+0x18))
10325     (stop *(ebp+0x1c) 1)
10326     # never gets here
10327 
10328 test-parse-mu-var-def:
10329     # 'var n: int'
10330     # . prologue
10331     55/push-ebp
10332     89/<- %ebp 4/r32/esp
10333     # setup
10334     8b/-> *Primitive-type-ids 0/r32/eax
10335     89/<- *Type-id 0/r32/eax  # stream-write
10336     (clear-stream _test-input-stream)
10337     (write _test-input-stream "n: int\n")  # caller has consumed the 'var'
10338     c7 0/subop/copy *Curr-block-depth 1/imm32
10339     # var out/esi: (handle stmt)
10340     68/push 0/imm32
10341     68/push 0/imm32
10342     89/<- %esi 4/r32/esp
10343     # var vars/ecx: (stack (addr var) 16)
10344     81 5/subop/subtract %esp 0xc0/imm32
10345     68/push 0xc0/imm32/size
10346     68/push 0/imm32/top
10347     89/<- %ecx 4/r32/esp
10348     (clear-stack %ecx)
10349     # convert
10350     (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0)
10351     # var out-addr/esi: (addr stmt)
10352     (lookup *esi *(esi+4))  # => eax
10353     89/<- %esi 0/r32/eax
10354     #
10355     (check-ints-equal *esi 2 "F - test-parse-mu-var-def/tag")  # Stmt-tag is var-def
10356     # var v/ecx: (addr var) = lookup(out->var)
10357     (lookup *(esi+4) *(esi+8))  # Vardef-var Vardef-var => eax
10358     89/<- %ecx 0/r32/eax
10359     # v->name
10360     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
10361     (check-strings-equal %eax "n" "F - test-parse-mu-var-def/var-name")
10362     # v->register
10363     (check-ints-equal *(ecx+0x18) 0 "F - test-parse-mu-var-def/var-register")  # Var-register
10364     # v->block-depth
10365     (check-ints-equal *(ecx+0x10) 1 "F - test-parse-mu-var-def/output-block-depth")  # Var-block-depth
10366     # v->type == int
10367     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
10368     (check-ints-equal *eax 1 "F - test-parse-mu-var-def/var-type:0")  # Type-tree-is-atom
10369     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-var-def/var-type:1")  # Type-tree-value
10370     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-var-def/var-type:2")  # Type-tree-right
10371     # . epilogue
10372     89/<- %esp 5/r32/ebp
10373     5d/pop-to-ebp
10374     c3/return
10375 
10376 test-parse-mu-reg-var-def:
10377     # 'var n/eax: int <- copy 0'
10378     # . prologue
10379     55/push-ebp
10380     89/<- %ebp 4/r32/esp
10381     # setup
10382     8b/-> *Primitive-type-ids 0/r32/eax
10383     89/<- *Type-id 0/r32/eax  # stream-write
10384     (clear-stream _test-input-stream)
10385     (write _test-input-stream "n/eax: int <- copy 0\n")  # caller has consumed the 'var'
10386     c7 0/subop/copy *Curr-block-depth 1/imm32
10387     # var out/esi: (handle stmt)
10388     68/push 0/imm32
10389     68/push 0/imm32
10390     89/<- %esi 4/r32/esp
10391     # var vars/ecx: (stack (addr var) 16)
10392     81 5/subop/subtract %esp 0xc0/imm32
10393     68/push 0xc0/imm32/size
10394     68/push 0/imm32/top
10395     89/<- %ecx 4/r32/esp
10396     (clear-stack %ecx)
10397     # convert
10398     (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0)
10399     # var out-addr/esi: (addr stmt)
10400     (lookup *esi *(esi+4))  # => eax
10401     89/<- %esi 0/r32/eax
10402     #
10403     (check-ints-equal *esi 3 "F - test-parse-mu-reg-var-def/tag")  # Stmt-tag is reg-var-def
10404     # var v/ecx: (addr var) = lookup(out->outputs->value)
10405     # . eax: (addr stmt-var) = lookup(out->outputs)
10406     (lookup *(esi+0x14) *(esi+0x18))  # Regvardef-outputs Regvardef-outputs => eax
10407     # .
10408     (check-ints-equal *(eax+8) 0 "F - test-parse-mu-reg-var-def/single-output")  # Stmt-var-next
10409     # . eax: (addr var) = lookup(eax->value)
10410     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10411     # . ecx = eax
10412     89/<- %ecx 0/r32/eax
10413     # v->name
10414     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
10415     (check-strings-equal %eax "n" "F - test-parse-mu-reg-var-def/output-name")  # Var-name
10416     # v->register
10417     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
10418     (check-strings-equal %eax "eax" "F - test-parse-mu-reg-var-def/output-register")
10419     # v->block-depth
10420     (check-ints-equal *(ecx+0x10) 1 "F - test-parse-mu-reg-var-def/output-block-depth")  # Var-block-depth
10421     # v->type == int
10422     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
10423     (check-ints-equal *eax 1 "F - test-parse-mu-reg-var-def/output-type:0")  # Type-tree-is-atom
10424     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-reg-var-def/output-type:1")  # Type-tree-value
10425     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-reg-var-def/output-type:2")  # Type-tree-right
10426     # . epilogue
10427     89/<- %esp 5/r32/ebp
10428     5d/pop-to-ebp
10429     c3/return
10430 
10431 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)
10432     # Carefully push any outputs on the vars stack _after_ reading the inputs
10433     # that may conflict with them.
10434     #
10435     # The only situation in which outputs are pushed here (when it's not a
10436     # 'var' vardef stmt), and so can possibly conflict with inputs, is if the
10437     # output is a function output.
10438     #
10439     # pseudocode:
10440     #   var name: slice
10441     #   allocate(Heap, Stmt-size, out)
10442     #   var out-addr: (addr stmt) = lookup(*out)
10443     #   out-addr->tag = stmt
10444     #   if stmt-has-outputs?(line)
10445     #     while true
10446     #       name = next-mu-token(line)
10447     #       if (name == '<-') break
10448     #       assert(is-identifier?(name))
10449     #       var v: (handle var) = lookup-var-or-find-in-fn-outputs(name, vars, fn)
10450     #       out-addr->outputs = append(v, out-addr->outputs)
10451     #   add-operation-and-inputs-to-stmt(out-addr, line, vars)
10452     #   for output in stmt->outputs:
10453     #     maybe-define-var(output, vars)
10454     #
10455     # . prologue
10456     55/push-ebp
10457     89/<- %ebp 4/r32/esp
10458     # . save registers
10459     50/push-eax
10460     51/push-ecx
10461     52/push-edx
10462     53/push-ebx
10463     57/push-edi
10464     # var name/ecx: slice
10465     68/push 0/imm32/end
10466     68/push 0/imm32/start
10467     89/<- %ecx 4/r32/esp
10468     # var is-deref?/edx: boolean = false
10469     ba/copy-to-edx 0/imm32/false
10470     # var v: (handle var)
10471     68/push 0/imm32
10472     68/push 0/imm32
10473     89/<- %ebx 4/r32/esp
10474     #
10475     (allocate Heap *Stmt-size *(ebp+0x14))
10476     # var out-addr/edi: (addr stmt) = lookup(*out)
10477     8b/-> *(ebp+0x14) 7/r32/edi
10478     (lookup *edi *(edi+4))  # => eax
10479     89/<- %edi 0/r32/eax
10480     # out-addr->tag = 1/stmt
10481     c7 0/subop/copy *edi 1/imm32/stmt1  # Stmt-tag
10482     {
10483       (stmt-has-outputs? *(ebp+8))
10484       3d/compare-eax-and 0/imm32/false
10485       0f 84/jump-if-= break/disp32
10486       {
10487 $parse-mu-stmt:read-outputs:
10488         # name = next-mu-token(line)
10489         (next-mu-token *(ebp+8) %ecx)
10490         # if slice-empty?(word-slice) break
10491         (slice-empty? %ecx)  # => eax
10492         3d/compare-eax-and 0/imm32/false
10493         0f 85/jump-if-!= break/disp32
10494         # if (name == "<-") break
10495         (slice-equal? %ecx "<-")  # => eax
10496         3d/compare-eax-and 0/imm32/false
10497         0f 85/jump-if-!= break/disp32
10498         # is-deref? = false
10499         ba/copy-to-edx 0/imm32/false
10500         # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
10501         8b/-> *ecx 0/r32/eax  # Slice-start
10502         8a/copy-byte *eax 0/r32/AL
10503         81 4/subop/and %eax 0xff/imm32
10504         3d/compare-eax-and 0x2a/imm32/asterisk
10505         {
10506           75/jump-if-!= break/disp8
10507           ff 0/subop/increment *ecx
10508           ba/copy-to-edx 1/imm32/true
10509         }
10510         # assert(is-identifier?(name))
10511         (is-identifier? %ecx)  # => eax
10512         3d/compare-eax-and 0/imm32/false
10513         0f 84/jump-if-= $parse-mu-stmt:abort/disp32
10514         #
10515         (lookup-var-or-find-in-fn-outputs %ecx *(ebp+0xc) *(ebp+0x10) %ebx *(ebp+0x18) *(ebp+0x1c))
10516         8d/copy-address *(edi+0x14) 0/r32/eax  # Stmt1-outputs
10517         (append-stmt-var Heap  *ebx *(ebx+4)  *(edi+0x14) *(edi+0x18)  %edx  %eax)  # Stmt1-outputs
10518         #
10519         e9/jump loop/disp32
10520       }
10521     }
10522     (add-operation-and-inputs-to-stmt %edi *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
10523 $parse-mu-stmt:define-outputs:
10524     # var output/edi: (addr stmt-var) = lookup(out-addr->outputs)
10525     (lookup *(edi+0x14) *(edi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
10526     89/<- %edi 0/r32/eax
10527     {
10528 $parse-mu-stmt:define-outputs-loop:
10529       # if (output == null) break
10530       81 7/subop/compare %edi 0/imm32
10531       74/jump-if-= break/disp8
10532       #
10533       (maybe-define-var *edi *(edi+4)  *(ebp+0xc))  # if output is a deref, then it's already been defined,
10534                                                     # and must be in vars. This call will be a no-op, but safe.
10535       # output = output->next
10536       (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
10537       89/<- %edi 0/r32/eax
10538       #
10539       eb/jump loop/disp8
10540     }
10541 $parse-mu-stmt:end:
10542     # . reclaim locals
10543     81 0/subop/add %esp 0x10/imm32
10544     # . restore registers
10545     5f/pop-to-edi
10546     5b/pop-to-ebx
10547     5a/pop-to-edx
10548     59/pop-to-ecx
10549     58/pop-to-eax
10550     # . epilogue
10551     89/<- %esp 5/r32/ebp
10552     5d/pop-to-ebp
10553     c3/return
10554 
10555 $parse-mu-stmt:abort:
10556     # error("invalid identifier '" name "'\n")
10557     (write-buffered *(ebp+0x18) "invalid identifier '")
10558     (write-slice-buffered *(ebp+0x18) %ecx)
10559     (write-buffered *(ebp+0x18) "'\n")
10560     (flush *(ebp+0x18))
10561     (stop *(ebp+0x1c) 1)
10562     # never gets here
10563 
10564 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)
10565     # pseudocode:
10566     #   stmt->name = slice-to-string(next-mu-token(line))
10567     #   while true
10568     #     name = next-mu-token(line)
10569     #     v = lookup-var-or-literal(name)
10570     #     stmt->inouts = append(v, stmt->inouts)
10571     #
10572     # . prologue
10573     55/push-ebp
10574     89/<- %ebp 4/r32/esp
10575     # . save registers
10576     50/push-eax
10577     51/push-ecx
10578     52/push-edx
10579     53/push-ebx
10580     56/push-esi
10581     57/push-edi
10582     # edi = stmt
10583     8b/-> *(ebp+8) 7/r32/edi
10584     # var name/ecx: slice
10585     68/push 0/imm32/end
10586     68/push 0/imm32/start
10587     89/<- %ecx 4/r32/esp
10588     # var is-deref?/edx: boolean = false
10589     ba/copy-to-edx 0/imm32/false
10590     # var v/esi: (handle var)
10591     68/push 0/imm32
10592     68/push 0/imm32
10593     89/<- %esi 4/r32/esp
10594 $add-operation-and-inputs-to-stmt:read-operation:
10595     (next-mu-token *(ebp+0xc) %ecx)
10596     8d/copy-address *(edi+4) 0/r32/eax  # Stmt1-operation or Regvardef-operationStmt1-operation or Regvardef-operation
10597     (slice-to-string Heap %ecx %eax)
10598     # var is-get?/ebx: boolean = (name == "get")
10599     (slice-equal? %ecx "get")  # => eax
10600     89/<- %ebx 0/r32/eax
10601     {
10602 $add-operation-and-inputs-to-stmt:read-inouts:
10603       # name = next-mu-token(line)
10604       (next-mu-token *(ebp+0xc) %ecx)
10605       # if slice-empty?(word-slice) break
10606       (slice-empty? %ecx)  # => eax
10607       3d/compare-eax-and 0/imm32/false
10608       0f 85/jump-if-!= break/disp32
10609       # if (name == "<-") abort
10610       (slice-equal? %ecx "<-")
10611       3d/compare-eax-and 0/imm32/false
10612       0f 85/jump-if-!= $add-operation-and-inputs-to-stmt:abort/disp32
10613       # if (is-get? && second operand) lookup or create offset
10614       {
10615         81 7/subop/compare %ebx 0/imm32/false
10616         74/jump-if-= break/disp8
10617         (lookup *(edi+0xc) *(edi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
10618         3d/compare-eax-and 0/imm32
10619         74/jump-if-= break/disp8
10620         (lookup-or-create-constant %eax %ecx %esi)
10621 #?         (lookup *esi *(esi+4))
10622 #?         (write-buffered Stderr "creating new output var ")
10623 #?         (write-int32-hex-buffered Stderr %eax)
10624 #?         (write-buffered Stderr " for field called ")
10625 #?         (write-slice-buffered Stderr %ecx)
10626 #?         (write-buffered Stderr "; var name ")
10627 #?         (lookup *eax *(eax+4))  # Var-name
10628 #?         (write-buffered Stderr %eax)
10629 #?         (write-buffered Stderr Newline)
10630 #?         (flush Stderr)
10631         e9/jump $add-operation-and-inputs-to-stmt:save-var/disp32
10632       }
10633       # is-deref? = false
10634       ba/copy-to-edx 0/imm32/false
10635       # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
10636       8b/-> *ecx 0/r32/eax  # Slice-start
10637       8a/copy-byte *eax 0/r32/AL
10638       81 4/subop/and %eax 0xff/imm32
10639       3d/compare-eax-and 0x2a/imm32/asterisk
10640       {
10641         75/jump-if-!= break/disp8
10642 $add-operation-and-inputs-to-stmt:inout-is-deref:
10643         ff 0/subop/increment *ecx
10644         ba/copy-to-edx 1/imm32/true
10645       }
10646       (lookup-var-or-literal %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
10647 $add-operation-and-inputs-to-stmt:save-var:
10648       8d/copy-address *(edi+0xc) 0/r32/eax
10649       (append-stmt-var Heap  *esi *(esi+4)  *(edi+0xc) *(edi+0x10)  %edx  %eax)  # Stmt1-inouts or Regvardef-inouts
10650       #
10651       e9/jump loop/disp32
10652     }
10653 $add-operation-and-inputs-to-stmt:end:
10654     # . reclaim locals
10655     81 0/subop/add %esp 0x10/imm32
10656     # . restore registers
10657     5f/pop-to-edi
10658     5e/pop-to-esi
10659     5b/pop-to-ebx
10660     5a/pop-to-edx
10661     59/pop-to-ecx
10662     58/pop-to-eax
10663     # . epilogue
10664     89/<- %esp 5/r32/ebp
10665     5d/pop-to-ebp
10666     c3/return
10667 
10668 $add-operation-and-inputs-to-stmt:abort:
10669     # error("fn ___: invalid identifier in '" line "'\n")
10670     (write-buffered *(ebp+0x18) "fn ")
10671     8b/-> *(ebp+0x14) 0/r32/eax
10672     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10673     (write-buffered *(ebp+0x18) %eax)
10674     (rewind-stream *(ebp+0xc))
10675     (write-buffered *(ebp+0x18) ": invalid identifier in '")
10676     (write-stream-data *(ebp+0x18) *(ebp+0xc))
10677     (write-buffered *(ebp+0x18) "'\n")
10678     (flush *(ebp+0x18))
10679     (stop *(ebp+0x1c) 1)
10680     # never gets here
10681 
10682 stmt-has-outputs?:  # line: (addr stream byte) -> result/eax: boolean
10683     # . prologue
10684     55/push-ebp
10685     89/<- %ebp 4/r32/esp
10686     # . save registers
10687     51/push-ecx
10688     # var word-slice/ecx: slice
10689     68/push 0/imm32/end
10690     68/push 0/imm32/start
10691     89/<- %ecx 4/r32/esp
10692     # result = false
10693     b8/copy-to-eax 0/imm32/false
10694     (rewind-stream *(ebp+8))
10695     {
10696       (next-mu-token *(ebp+8) %ecx)
10697       # if slice-empty?(word-slice) break
10698       (slice-empty? %ecx)
10699       3d/compare-eax-and 0/imm32/false
10700       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
10701       0f 85/jump-if-!= break/disp32
10702       # if slice-starts-with?(word-slice, '#') break
10703       # . eax = *word-slice->start
10704       8b/-> *ecx 0/r32/eax
10705       8a/copy-byte *eax 0/r32/AL
10706       81 4/subop/and %eax 0xff/imm32
10707       # . if (eax == '#') break
10708       3d/compare-eax-and 0x23/imm32/hash
10709       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
10710       0f 84/jump-if-= break/disp32
10711       # if slice-equal?(word-slice, '<-') return true
10712       (slice-equal? %ecx "<-")
10713       3d/compare-eax-and 0/imm32/false
10714       74/jump-if-= loop/disp8
10715       b8/copy-to-eax 1/imm32/true
10716     }
10717 $stmt-has-outputs:end:
10718     (rewind-stream *(ebp+8))
10719     # . reclaim locals
10720     81 0/subop/add %esp 8/imm32
10721     # . restore registers
10722     59/pop-to-ecx
10723     # . epilogue
10724     89/<- %esp 5/r32/ebp
10725     5d/pop-to-ebp
10726     c3/return
10727 
10728 # if 'name' starts with a digit, create a new literal var for it
10729 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found
10730 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)
10731     # . prologue
10732     55/push-ebp
10733     89/<- %ebp 4/r32/esp
10734     # . save registers
10735     50/push-eax
10736     51/push-ecx
10737     56/push-esi
10738     # esi = name
10739     8b/-> *(ebp+8) 6/r32/esi
10740     # if slice-empty?(name) abort
10741     (slice-empty? %esi)  # => eax
10742     3d/compare-eax-and 0/imm32/false
10743     0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32
10744     # var c/ecx: byte = *name->start
10745     8b/-> *esi 1/r32/ecx
10746     8a/copy-byte *ecx 1/r32/CL
10747     81 4/subop/and %ecx 0xff/imm32
10748     # if (is-decimal-digit?(c) || c == '-') return new var(name)
10749     {
10750       81 7/subop/compare %ecx 0x2d/imm32/dash
10751       74/jump-if-= $lookup-var-or-literal:literal/disp8
10752       (is-decimal-digit? %ecx)  # => eax
10753       3d/compare-eax-and 0/imm32/false
10754       74/jump-if-= break/disp8
10755 $lookup-var-or-literal:literal:
10756       (new-literal-integer Heap %esi *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
10757       eb/jump $lookup-var-or-literal:end/disp8
10758     }
10759     # else if (c == '"') return new var(name)
10760     {
10761       81 7/subop/compare %ecx 0x22/imm32/dquote
10762       75/jump-if-!= break/disp8
10763 $lookup-var-or-literal:literal-string:
10764       (new-literal Heap %esi *(ebp+0x10))
10765       eb/jump $lookup-var-or-literal:end/disp8
10766     }
10767     # otherwise return lookup-var(name, vars)
10768     {
10769 $lookup-var-or-literal:var:
10770       (lookup-var %esi *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
10771     }
10772 $lookup-var-or-literal:end:
10773     # . restore registers
10774     5e/pop-to-esi
10775     59/pop-to-ecx
10776     58/pop-to-eax
10777     # . epilogue
10778     89/<- %esp 5/r32/ebp
10779     5d/pop-to-ebp
10780     c3/return
10781 
10782 $lookup-var-or-literal:abort:
10783     (write-buffered *(ebp+0x18) "fn ")
10784     8b/-> *(ebp+0x14) 0/r32/eax
10785     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10786     (write-buffered *(ebp+0x18) %eax)
10787     (write-buffered *(ebp+0x18) ": empty variable!")
10788     (flush *(ebp+0x18))
10789     (stop *(ebp+0x1c) 1)
10790     # never gets here
10791 
10792 # return first 'name' from the top (back) of 'vars' and abort if not found
10793 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)
10794     # . prologue
10795     55/push-ebp
10796     89/<- %ebp 4/r32/esp
10797     # . save registers
10798     50/push-eax
10799     #
10800     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
10801     # if (*out == 0) abort
10802     8b/-> *(ebp+0x10) 0/r32/eax
10803     81 7/subop/compare *eax 0/imm32
10804     74/jump-if-= $lookup-var:abort/disp8
10805 $lookup-var:end:
10806     # . restore registers
10807     58/pop-to-eax
10808     # . epilogue
10809     89/<- %esp 5/r32/ebp
10810     5d/pop-to-ebp
10811     c3/return
10812 
10813 $lookup-var:abort:
10814     (write-buffered *(ebp+0x18) "fn ")
10815     8b/-> *(ebp+0x14) 0/r32/eax
10816     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10817     (write-buffered *(ebp+0x18) %eax)
10818     (write-buffered *(ebp+0x18) ": unknown variable '")
10819     (write-slice-buffered *(ebp+0x18) *(ebp+8))
10820     (write-buffered *(ebp+0x18) "'\n")
10821     (flush *(ebp+0x18))
10822     (stop *(ebp+0x1c) 1)
10823     # never gets here
10824 
10825 # return first 'name' from the top (back) of 'vars', and 0/null if not found
10826 # ensure that 'name' if in a register is the topmost variable in that register
10827 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)
10828     # pseudocode:
10829     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
10830     #   var min = vars->data
10831     #   while curr >= min
10832     #     var v: (handle var) = *curr
10833     #     if v->name == name
10834     #       return
10835     #     curr -= 12
10836     #
10837     # . prologue
10838     55/push-ebp
10839     89/<- %ebp 4/r32/esp
10840     # . save registers
10841     50/push-eax
10842     51/push-ecx
10843     52/push-edx
10844     53/push-ebx
10845     56/push-esi
10846     57/push-edi
10847     # clear out
10848     (zero-out *(ebp+0x10) *Handle-size)
10849     # esi = vars
10850     8b/-> *(ebp+0xc) 6/r32/esi
10851     # ebx = vars->top
10852     8b/-> *esi 3/r32/ebx
10853     # if (vars->top > vars->size) abort
10854     3b/compare<- *(esi+4) 0/r32/eax
10855     0f 8f/jump-if-> $lookup-var-helper:error1/disp32
10856     # var min/edx: (addr handle var) = vars->data
10857     8d/copy-address *(esi+8) 2/r32/edx
10858     # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
10859     8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
10860     # var var-in-reg/edi: 8 addrs
10861     68/push 0/imm32
10862     68/push 0/imm32
10863     68/push 0/imm32
10864     68/push 0/imm32
10865     68/push 0/imm32
10866     68/push 0/imm32
10867     68/push 0/imm32
10868     68/push 0/imm32
10869     89/<- %edi 4/r32/esp
10870     {
10871 $lookup-var-helper:loop:
10872       # if (curr < min) return
10873       39/compare %ebx 2/r32/edx
10874       0f 82/jump-if-addr< break/disp32
10875       # var v/ecx: (addr var) = lookup(*curr)
10876       (lookup *ebx *(ebx+4))  # => eax
10877       89/<- %ecx 0/r32/eax
10878       # var vn/eax: (addr array byte) = lookup(v->name)
10879       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
10880       # if (vn == name) return curr
10881       (slice-equal? *(ebp+8) %eax)  # => eax
10882       3d/compare-eax-and 0/imm32/false
10883       {
10884         74/jump-if-= break/disp8
10885 $lookup-var-helper:found:
10886         # var vr/eax: (addr array byte) = lookup(v->register)
10887         (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
10888         3d/compare-eax-and 0/imm32
10889         {
10890           74/jump-if-= break/disp8
10891 $lookup-var-helper:found-register:
10892           # var reg/eax: int = get(Registers, vr)
10893           (get Mu-registers %eax 0xc "Mu-registers")  # => eax
10894           8b/-> *eax 0/r32/eax
10895           # if (var-in-reg[reg]) error
10896           8b/-> *(edi+eax<<2) 0/r32/eax
10897           3d/compare-eax-and 0/imm32
10898           0f 85/jump-if-!= $lookup-var-helper:error2/disp32
10899         }
10900 $lookup-var-helper:return:
10901         # esi = out
10902         8b/-> *(ebp+0x10) 6/r32/esi
10903         # *out = *curr
10904         8b/-> *ebx 0/r32/eax
10905         89/<- *esi 0/r32/eax
10906         8b/-> *(ebx+4) 0/r32/eax
10907         89/<- *(esi+4) 0/r32/eax
10908         # return
10909         eb/jump $lookup-var-helper:end/disp8
10910       }
10911       # 'name' not yet found; update var-in-reg if v in register
10912       # . var vr/eax: (addr array byte) = lookup(v->register)
10913       (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
10914       # . if (var == 0) continue
10915       3d/compare-eax-and 0/imm32
10916       74/jump-if-= $lookup-var-helper:continue/disp8
10917       # . var reg/eax: int = get(Registers, vr)
10918       (get Mu-registers %eax 0xc "Mu-registers")  # => eax
10919       8b/-> *eax 0/r32/eax
10920       # . if (var-in-reg[reg] == 0) var-in-reg[reg] = v
10921       81 7/subop/compare *(edi+eax<<2) 0/imm32
10922       75/jump-if-!= $lookup-var-helper:continue/disp8
10923       89/<- *(edi+eax<<2) 1/r32/ecx
10924 $lookup-var-helper:continue:
10925       # curr -= 12
10926       81 5/subop/subtract %ebx 0xc/imm32
10927       e9/jump loop/disp32
10928     }
10929 $lookup-var-helper:end:
10930     # . reclaim locals
10931     81 0/subop/add %esp 0x20/imm32
10932     # . restore registers
10933     5f/pop-to-edi
10934     5e/pop-to-esi
10935     5b/pop-to-ebx
10936     5a/pop-to-edx
10937     59/pop-to-ecx
10938     58/pop-to-eax
10939     # . epilogue
10940     89/<- %esp 5/r32/ebp
10941     5d/pop-to-ebp
10942     c3/return
10943 
10944 $lookup-var-helper:error1:
10945     (write-buffered *(ebp+0x18) "fn ")
10946     8b/-> *(ebp+0x14) 0/r32/eax
10947     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10948     (write-buffered *(ebp+0x18) %eax)
10949     (write-buffered *(ebp+0x18) ": malformed stack when looking up '")
10950     (write-slice-buffered *(ebp+0x18) *(ebp+8))
10951     (write-buffered *(ebp+0x18) "'\n")
10952     (flush *(ebp+0x18))
10953     (stop *(ebp+0x1c) 1)
10954     # never gets here
10955 
10956 $lookup-var-helper:error2:
10957     # eax contains the conflicting var at this point
10958     (write-buffered *(ebp+0x18) "fn ")
10959     50/push-eax
10960     8b/-> *(ebp+0x14) 0/r32/eax
10961     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10962     (write-buffered *(ebp+0x18) %eax)
10963     58/pop-eax
10964     (write-buffered *(ebp+0x18) ": register ")
10965     50/push-eax
10966     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
10967     (write-buffered *(ebp+0x18) %eax)
10968     58/pop-to-eax
10969     (write-buffered *(ebp+0x18) " reads var '")
10970     (write-slice-buffered *(ebp+0x18) *(ebp+8))
10971     (write-buffered *(ebp+0x18) "' after writing var '")
10972     (lookup *eax *(eax+4))  # Var-name Var-name => eax
10973     (write-buffered *(ebp+0x18) %eax)
10974     (write-buffered *(ebp+0x18) "'\n")
10975     (flush *(ebp+0x18))
10976     (stop *(ebp+0x1c) 1)
10977     # never gets here
10978 
10979 dump-vars:  # vars: (addr stack live-var)
10980     # pseudocode:
10981     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
10982     #   var min = vars->data
10983     #   while curr >= min
10984     #     var v: (handle var) = *curr
10985     #     print v
10986     #     curr -= 12
10987     #
10988     # . prologue
10989     55/push-ebp
10990     89/<- %ebp 4/r32/esp
10991     # . save registers
10992     52/push-edx
10993     53/push-ebx
10994     56/push-esi
10995     # esi = vars
10996     8b/-> *(ebp+8) 6/r32/esi
10997     # ebx = vars->top
10998     8b/-> *esi 3/r32/ebx
10999     # var min/edx: (addr handle var) = vars->data
11000     8d/copy-address *(esi+8) 2/r32/edx
11001     # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
11002     8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
11003     {
11004 $dump-vars:loop:
11005       # if (curr < min) return
11006       39/compare %ebx 2/r32/edx
11007       0f 82/jump-if-addr< break/disp32
11008       #
11009       (write-buffered Stderr "  var@")
11010       (dump-var 2 %ebx)
11011       # curr -= 12
11012       81 5/subop/subtract %ebx 0xc/imm32
11013       e9/jump loop/disp32
11014     }
11015 $dump-vars:end:
11016     # . restore registers
11017     5e/pop-to-esi
11018     5b/pop-to-ebx
11019     5a/pop-to-edx
11020     # . epilogue
11021     89/<- %esp 5/r32/ebp
11022     5d/pop-to-ebp
11023     c3/return
11024 
11025 == data
11026 # Like Registers, but no esp or ebp
11027 Mu-registers:  # (addr stream {(handle array byte), int})
11028   # a table is a stream
11029   0xa8/imm32/write
11030   0/imm32/read
11031   0xa8/imm32/length
11032   # data
11033   # general-purpose registers
11034   # it is perfectly ok to use fake alloc-ids -- as long as you never try to reclaim them
11035   0x11/imm32/alloc-id $Mu-register-eax/imm32 0/imm32
11036   0x11/imm32/alloc-id $Mu-register-ecx/imm32 1/imm32
11037   0x11/imm32/alloc-id $Mu-register-edx/imm32 2/imm32
11038   0x11/imm32/alloc-id $Mu-register-ebx/imm32 3/imm32
11039   0x11/imm32/alloc-id $Mu-register-esi/imm32 6/imm32
11040   0x11/imm32/alloc-id $Mu-register-edi/imm32 7/imm32
11041   # floating-point registers
11042   0x11/imm32/alloc-id $Mu-register-xmm0/imm32 0/imm32
11043   0x11/imm32/alloc-id $Mu-register-xmm1/imm32 1/imm32
11044   0x11/imm32/alloc-id $Mu-register-xmm2/imm32 2/imm32
11045   0x11/imm32/alloc-id $Mu-register-xmm3/imm32 3/imm32
11046   0x11/imm32/alloc-id $Mu-register-xmm4/imm32 4/imm32
11047   0x11/imm32/alloc-id $Mu-register-xmm5/imm32 5/imm32
11048   0x11/imm32/alloc-id $Mu-register-xmm6/imm32 6/imm32
11049   0x11/imm32/alloc-id $Mu-register-xmm7/imm32 7/imm32
11050 
11051 $Mu-register-eax:
11052   0x11/imm32/alloc-id
11053   3/imm32/size
11054   0x65/e 0x61/a 0x78/x
11055 
11056 $Mu-register-ecx:
11057   0x11/imm32/alloc-id
11058   3/imm32/size
11059   0x65/e 0x63/c 0x78/x
11060 
11061 $Mu-register-edx:
11062   0x11/imm32/alloc-id
11063   3/imm32/size
11064   0x65/e 0x64/d 0x78/x
11065 
11066 $Mu-register-ebx:
11067   0x11/imm32/alloc-id
11068   3/imm32/size
11069   0x65/e 0x62/b 0x78/x
11070 
11071 $Mu-register-esi:
11072   0x11/imm32/alloc-id
11073   3/imm32/size
11074   0x65/e 0x73/s 0x69/i
11075 
11076 $Mu-register-edi:
11077   0x11/imm32/alloc-id
11078   3/imm32/size
11079   0x65/e 0x64/d 0x69/i
11080 
11081 $Mu-register-xmm0:
11082   0x11/imm32/alloc-id:fake:payload
11083   # "xmm0"
11084   0x4/imm32/size
11085   0x78/x 0x6d/m 0x6d/m 0x30/0
11086 
11087 $Mu-register-xmm1:
11088   0x11/imm32/alloc-id:fake:payload
11089   # "xmm1"
11090   0x4/imm32/size
11091   0x78/x 0x6d/m 0x6d/m 0x31/1
11092 
11093 $Mu-register-xmm2:
11094   0x11/imm32/alloc-id:fake:payload
11095   # "xmm2"
11096   0x4/imm32/size
11097   0x78/x 0x6d/m 0x6d/m 0x32/2
11098 
11099 $Mu-register-xmm3:
11100   0x11/imm32/alloc-id:fake:payload
11101   # "xmm3"
11102   0x4/imm32/size
11103   0x78/x 0x6d/m 0x6d/m 0x33/3
11104 
11105 $Mu-register-xmm4:
11106   0x11/imm32/alloc-id:fake:payload
11107   # "xmm4"
11108   0x4/imm32/size
11109   0x78/x 0x6d/m 0x6d/m 0x34/4
11110 
11111 $Mu-register-xmm5:
11112   0x11/imm32/alloc-id:fake:payload
11113   # "xmm5"
11114   0x4/imm32/size
11115   0x78/x 0x6d/m 0x6d/m 0x35/5
11116 
11117 $Mu-register-xmm6:
11118   0x11/imm32/alloc-id:fake:payload
11119   # "xmm6"
11120   0x4/imm32/size
11121   0x78/x 0x6d/m 0x6d/m 0x36/6
11122 
11123 $Mu-register-xmm7:
11124   0x11/imm32/alloc-id:fake:payload
11125   # "xmm7"
11126   0x4/imm32/size
11127   0x78/x 0x6d/m 0x6d/m 0x37/7
11128 
11129 == code
11130 
11131 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found
11132 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)
11133     # . prologue
11134     55/push-ebp
11135     89/<- %ebp 4/r32/esp
11136     # . save registers
11137     50/push-eax
11138     #
11139     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))  # arg order slightly different; 'fn' is deemphasized
11140     {
11141       # if (out != 0) return
11142       8b/-> *(ebp+0x14) 0/r32/eax
11143       81 7/subop/compare *eax 0/imm32
11144       75/jump-if-!= break/disp8
11145       # if name is one of fn's outputs, return it
11146       (find-in-function-outputs *(ebp+0x10) *(ebp+8) *(ebp+0x14))
11147       8b/-> *(ebp+0x14) 0/r32/eax
11148       81 7/subop/compare *eax 0/imm32
11149       # otherwise abort
11150       0f 84/jump-if-= $lookup-or-define-var:abort/disp32
11151     }
11152 $lookup-or-define-var:end:
11153     # . restore registers
11154     58/pop-to-eax
11155     # . epilogue
11156     89/<- %esp 5/r32/ebp
11157     5d/pop-to-ebp
11158     c3/return
11159 
11160 $lookup-or-define-var:abort:
11161     (write-buffered *(ebp+0x18) "unknown variable '")
11162     (write-slice-buffered *(ebp+0x18) *(ebp+8))
11163     (write-buffered *(ebp+0x18) "'\n")
11164     (flush *(ebp+0x18))
11165     (stop *(ebp+0x1c) 1)
11166     # never gets here
11167 
11168 find-in-function-outputs:  # fn: (addr function), name: (addr slice), out: (addr handle var)
11169     # . prologue
11170     55/push-ebp
11171     89/<- %ebp 4/r32/esp
11172     # . save registers
11173     50/push-eax
11174     51/push-ecx
11175     # var curr/ecx: (addr list var) = lookup(fn->outputs)
11176     8b/-> *(ebp+8) 1/r32/ecx
11177     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
11178     89/<- %ecx 0/r32/eax
11179     # while curr != null
11180     {
11181       81 7/subop/compare %ecx 0/imm32
11182       74/jump-if-= break/disp8
11183       # var v/eax: (addr var) = lookup(curr->value)
11184       (lookup *ecx *(ecx+4))  # List-value List-value => eax
11185       # var s/eax: (addr array byte) = lookup(v->name)
11186       (lookup *eax *(eax+4))  # Var-name Var-name => eax
11187       # if (s == name) return curr->value
11188       (slice-equal? *(ebp+0xc) %eax)  # => eax
11189       3d/compare-eax-and 0/imm32/false
11190       {
11191         74/jump-if-= break/disp8
11192         # var edi = out
11193         57/push-edi
11194         8b/-> *(ebp+0x10) 7/r32/edi
11195         # *out = curr->value
11196         8b/-> *ecx 0/r32/eax
11197         89/<- *edi 0/r32/eax
11198         8b/-> *(ecx+4) 0/r32/eax
11199         89/<- *(edi+4) 0/r32/eax
11200         #
11201         5f/pop-to-edi
11202         eb/jump $find-in-function-outputs:end/disp8
11203       }
11204       # curr = curr->next
11205       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
11206       89/<- %ecx 0/r32/eax
11207       #
11208       eb/jump loop/disp8
11209     }
11210     b8/copy-to-eax 0/imm32
11211 $find-in-function-outputs:end:
11212     # . restore registers
11213     59/pop-to-ecx
11214     58/pop-to-eax
11215     # . epilogue
11216     89/<- %esp 5/r32/ebp
11217     5d/pop-to-ebp
11218     c3/return
11219 
11220 # push 'out' to 'vars' if not already there; it's assumed to be a fn output
11221 maybe-define-var:  # out: (handle var), vars: (addr stack live-var)
11222     # . prologue
11223     55/push-ebp
11224     89/<- %ebp 4/r32/esp
11225     # . save registers
11226     50/push-eax
11227     # var out-addr/eax: (addr var)
11228     (lookup *(ebp+8) *(ebp+0xc))  # => eax
11229     #
11230     (binding-exists? %eax *(ebp+0x10))  # => eax
11231     3d/compare-eax-and 0/imm32/false
11232     75/jump-if-!= $maybe-define-var:end/disp8
11233     # otherwise update vars
11234     (push *(ebp+0x10) *(ebp+8))
11235     (push *(ebp+0x10) *(ebp+0xc))
11236     (push *(ebp+0x10) 0)  # 'out' is always a fn output; never spill it
11237 $maybe-define-var:end:
11238     # . restore registers
11239     58/pop-to-eax
11240     # . epilogue
11241     89/<- %esp 5/r32/ebp
11242     5d/pop-to-ebp
11243     c3/return
11244 
11245 # simpler version of lookup-var-helper
11246 binding-exists?:  # target: (addr var), vars: (addr stack live-var) -> result/eax: boolean
11247     # pseudocode:
11248     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
11249     #   var min = vars->data
11250     #   while curr >= min
11251     #     var v: (handle var) = *curr
11252     #     if v->name == target->name
11253     #       return true
11254     #     curr -= 12
11255     #   return false
11256     #
11257     # . prologue
11258     55/push-ebp
11259     89/<- %ebp 4/r32/esp
11260     # . save registers
11261     51/push-ecx
11262     52/push-edx
11263     56/push-esi
11264     # var target-name/ecx: (addr array byte) = lookup(target->name)
11265     8b/-> *(ebp+8) 0/r32/eax
11266     (lookup *eax *(eax+4))  # Var-name Var-name => eax
11267     89/<- %ecx 0/r32/eax
11268     # esi = vars
11269     8b/-> *(ebp+0xc) 6/r32/esi
11270     # eax = vars->top
11271     8b/-> *esi 0/r32/eax
11272     # var min/edx: (addr handle var) = vars->data
11273     8d/copy-address *(esi+8) 2/r32/edx
11274     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
11275     8d/copy-address *(esi+eax-4) 6/r32/esi  # vars + 8 + vars->type - 12
11276     {
11277 $binding-exists?:loop:
11278       # if (curr < min) return
11279       39/compare %esi 2/r32/edx
11280       0f 82/jump-if-addr< break/disp32
11281       # var v/eax: (addr var) = lookup(*curr)
11282       (lookup *esi *(esi+4))  # => eax
11283       # var vn/eax: (addr array byte) = lookup(v->name)
11284       (lookup *eax *(eax+4))  # Var-name Var-name => eax
11285       # if (vn == target-name) return true
11286       (string-equal? %ecx %eax)  # => eax
11287       3d/compare-eax-and 0/imm32/false
11288       75/jump-if-!= $binding-exists?:end/disp8  # eax already contains true
11289       # curr -= 12
11290       81 5/subop/subtract %esi 0xc/imm32
11291       e9/jump loop/disp32
11292     }
11293     b8/copy-to-eax 0/imm32/false
11294 $binding-exists?:end:
11295     # . restore registers
11296     5e/pop-to-esi
11297     5a/pop-to-edx
11298     59/pop-to-ecx
11299     # . epilogue
11300     89/<- %esp 5/r32/ebp
11301     5d/pop-to-ebp
11302     c3/return
11303 
11304 test-parse-mu-stmt:
11305     # . prologue
11306     55/push-ebp
11307     89/<- %ebp 4/r32/esp
11308     # setup
11309     8b/-> *Primitive-type-ids 0/r32/eax
11310     89/<- *Type-id 0/r32/eax  # stream-write
11311     (clear-stream _test-input-stream)
11312     (write _test-input-stream "increment n\n")
11313     # var vars/ecx: (stack (addr var) 16)
11314     81 5/subop/subtract %esp 0xc0/imm32
11315     68/push 0xc0/imm32/size
11316     68/push 0/imm32/top
11317     89/<- %ecx 4/r32/esp
11318     (clear-stack %ecx)
11319     # var v/edx: (handle var)
11320     68/push 0/imm32
11321     68/push 0/imm32
11322     89/<- %edx 4/r32/esp
11323     # var s/eax: (handle array byte)
11324     68/push 0/imm32
11325     68/push 0/imm32
11326     89/<- %eax 4/r32/esp
11327     # v = new var("n")
11328     (copy-array Heap "n" %eax)
11329     (new-var Heap *eax *(eax+4) %edx)
11330     #
11331     (push %ecx *edx)
11332     (push %ecx *(edx+4))
11333     (push %ecx 0)
11334     # var out/eax: (handle stmt)
11335     68/push 0/imm32
11336     68/push 0/imm32
11337     89/<- %eax 4/r32/esp
11338     # convert
11339     (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
11340     # var out-addr/edx: (addr stmt) = lookup(*out)
11341     (lookup *eax *(eax+4))  # => eax
11342     89/<- %edx 0/r32/eax
11343     # out->tag
11344     (check-ints-equal *edx 1 "F - test-parse-mu-stmt/tag")  # Stmt-tag is Stmt1
11345     # out->operation
11346     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
11347     (check-strings-equal %eax "increment" "F - test-parse-mu-stmt/name")  # Stmt1-operation
11348     # out->inouts->value->name
11349     # . eax = out->inouts
11350     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11351     # . eax = out->inouts->value
11352     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11353     # . eax = out->inouts->value->name
11354     (lookup *eax *(eax+4))  # Var-name Var-name => eax
11355     # .
11356     (check-strings-equal %eax "n" "F - test-parse-mu-stmt/inout:0")
11357     # . epilogue
11358     89/<- %esp 5/r32/ebp
11359     5d/pop-to-ebp
11360     c3/return
11361 
11362 test-parse-mu-stmt-with-comma:
11363     # . prologue
11364     55/push-ebp
11365     89/<- %ebp 4/r32/esp
11366     # setup
11367     8b/-> *Primitive-type-ids 0/r32/eax
11368     89/<- *Type-id 0/r32/eax  # stream-write
11369     (clear-stream _test-input-stream)
11370     (write _test-input-stream "copy-to n, 3\n")
11371     # var vars/ecx: (stack (addr var) 16)
11372     81 5/subop/subtract %esp 0xc0/imm32
11373     68/push 0xc0/imm32/size
11374     68/push 0/imm32/top
11375     89/<- %ecx 4/r32/esp
11376     (clear-stack %ecx)
11377     # var v/edx: (handle var)
11378     68/push 0/imm32
11379     68/push 0/imm32
11380     89/<- %edx 4/r32/esp
11381     # var s/eax: (handle array byte)
11382     68/push 0/imm32
11383     68/push 0/imm32
11384     89/<- %eax 4/r32/esp
11385     # v = new var("n")
11386     (copy-array Heap "n" %eax)
11387     (new-var Heap *eax *(eax+4) %edx)
11388     #
11389     (push %ecx *edx)
11390     (push %ecx *(edx+4))
11391     (push %ecx 0)
11392     # var out/eax: (handle stmt)
11393     68/push 0/imm32
11394     68/push 0/imm32
11395     89/<- %eax 4/r32/esp
11396     # convert
11397     (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
11398     # var out-addr/edx: (addr stmt) = lookup(*out)
11399     (lookup *eax *(eax+4))  # => eax
11400     89/<- %edx 0/r32/eax
11401     # out->tag
11402     (check-ints-equal *edx 1 "F - test-parse-mu-stmt-with-comma/tag")  # Stmt-tag is Stmt1
11403     # out->operation
11404     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
11405     (check-strings-equal %eax "copy-to" "F - test-parse-mu-stmt-with-comma/name")  # Stmt1-operation
11406     # out->inouts->value->name
11407     # . eax = out->inouts
11408     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11409     # . eax = out->inouts->value
11410     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11411     # . eax = out->inouts->value->name
11412     (lookup *eax *(eax+4))  # Var-name Var-name => eax
11413     # .
11414     (check-strings-equal %eax "n" "F - test-parse-mu-stmt-with-comma/inout:0")
11415     # . epilogue
11416     89/<- %esp 5/r32/ebp
11417     5d/pop-to-ebp
11418     c3/return
11419 
11420 new-var:  # ad: (addr allocation-descriptor), name: (handle array byte), out: (addr handle var)
11421     # . prologue
11422     55/push-ebp
11423     89/<- %ebp 4/r32/esp
11424     # . save registers
11425     50/push-eax
11426     51/push-ecx
11427     # ecx = out
11428     8b/-> *(ebp+0x14) 1/r32/ecx
11429     #
11430     (allocate *(ebp+8) *Var-size %ecx)
11431     # var out-addr/eax: (addr var)
11432     (lookup *ecx *(ecx+4))  # => eax
11433     # out-addr->name = name
11434     8b/-> *(ebp+0xc) 1/r32/ecx
11435     89/<- *eax 1/r32/ecx  # Var-name
11436     8b/-> *(ebp+0x10) 1/r32/ecx
11437     89/<- *(eax+4) 1/r32/ecx  # Var-name
11438 #?     (write-buffered Stderr "var ")
11439 #?     (lookup *(ebp+0xc) *(ebp+0x10))
11440 #?     (write-buffered Stderr %eax)
11441 #?     (write-buffered Stderr " at ")
11442 #?     8b/-> *(ebp+0x14) 1/r32/ecx
11443 #?     (lookup *ecx *(ecx+4))  # => eax
11444 #?     (write-int32-hex-buffered Stderr %eax)
11445 #?     (write-buffered Stderr Newline)
11446 #?     (flush Stderr)
11447 $new-var:end:
11448     # . restore registers
11449     59/pop-to-ecx
11450     58/pop-to-eax
11451     # . epilogue
11452     89/<- %esp 5/r32/ebp
11453     5d/pop-to-ebp
11454     c3/return
11455 
11456 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)
11457     # . prologue
11458     55/push-ebp
11459     89/<- %ebp 4/r32/esp
11460     # . save registers
11461     50/push-eax
11462     51/push-ecx
11463     # if (!is-hex-int?(name)) abort
11464     (is-hex-int? *(ebp+0xc))  # => eax
11465     3d/compare-eax-and 0/imm32/false
11466     0f 84/jump-if-= $new-literal-integer:abort/disp32
11467     # a little more error-checking
11468     (check-mu-hex-int *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c))
11469     # out = new var(s)
11470     (new-var-from-slice *(ebp+8) *(ebp+0xc) *(ebp+0x10))
11471     # var out-addr/ecx: (addr var) = lookup(*out)
11472     8b/-> *(ebp+0x10) 0/r32/eax
11473     (lookup *eax *(eax+4))  # => eax
11474     89/<- %ecx 0/r32/eax
11475     # out-addr->block-depth = *Curr-block-depth
11476     8b/-> *Curr-block-depth 0/r32/eax
11477     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
11478     # out-addr->type = new tree()
11479     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
11480     (allocate *(ebp+8) *Type-tree-size %eax)
11481     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
11482     c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
11483     # nothing else to do; default type is 'literal'
11484 $new-literal-integer:end:
11485     # . reclaim locals
11486     81 0/subop/add %esp 8/imm32
11487     # . restore registers
11488     59/pop-to-ecx
11489     58/pop-to-eax
11490     # . epilogue
11491     89/<- %esp 5/r32/ebp
11492     5d/pop-to-ebp
11493     c3/return
11494 
11495 $new-literal-integer:abort:
11496     (write-buffered *(ebp+0x18) "fn ")
11497     8b/-> *(ebp+0x14) 0/r32/eax
11498     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11499     (write-buffered *(ebp+0x18) %eax)
11500     (write-buffered *(ebp+0x18) ": variable '")
11501     (write-slice-buffered *(ebp+0x18) *(ebp+0xc))
11502     (write-buffered *(ebp+0x18) "' cannot begin with a digit (or do you have a typo in a number?)\n")
11503     (flush *(ebp+0x18))
11504     (stop *(ebp+0x1c) 1)
11505     # never gets here
11506 
11507 # precondition: name is a valid hex integer; require a '0x' prefix
11508 check-mu-hex-int:  # name: (addr slice), err: (addr buffered-file), ed: (addr exit-descriptor)
11509     # . prologue
11510     55/push-ebp
11511     89/<- %ebp 4/r32/esp
11512     # . save registers
11513     50/push-eax
11514     51/push-ecx
11515     52/push-edx
11516     # ecx = name
11517     8b/-> *(ebp+8) 1/r32/ecx
11518     # var start/edx: (addr byte) = name->start
11519     8b/-> *ecx 2/r32/edx
11520     # if (*start == '-') ++start
11521     b8/copy-to-eax 0/imm32
11522     8a/copy-byte *edx 0/r32/AL
11523     3d/compare-eax-and 0x2d/imm32/dash
11524     {
11525       75/jump-if-!= break/disp8
11526       42/increment-edx
11527     }
11528     # var end/ecx: (addr byte) = name->end
11529     8b/-> *(ecx+4) 1/r32/ecx
11530     # var len/eax: int = name->end - name->start
11531     89/<- %eax 1/r32/ecx
11532     29/subtract-from %eax 2/r32/edx
11533     # if (len <= 1) return
11534     3d/compare-eax-with 1/imm32
11535     0f 8e/jump-if-<= $check-mu-hex-int:end/disp32
11536 $check-mu-hex-int:length->-1:
11537     # if slice-starts-with?({start, end}, "0x") return
11538     # . var tmp = {start, end}
11539     51/push-ecx
11540     52/push-edx
11541     89/<- %eax 4/r32/esp
11542     # .
11543     (slice-starts-with? %eax "0x")  # => eax
11544     # . reclaim tmp
11545     81 0/subop/add %esp 8/imm32
11546     # .
11547     3d/compare-eax-with 0/imm32/false
11548     75/jump-if-!= $check-mu-hex-int:end/disp8
11549 $check-mu-hex-int:abort:
11550     # otherwise abort
11551     (write-buffered *(ebp+0xc) "literal integers are always hex in Mu; either start '")
11552     (write-slice-buffered *(ebp+0xc) *(ebp+8))
11553     (write-buffered *(ebp+0xc) "' with a '0x' to be unambiguous, or convert it to decimal.\n")
11554     (flush *(ebp+0xc))
11555     (stop *(ebp+0x10) 1)
11556 $check-mu-hex-int:end:
11557     # . restore registers
11558     5a/pop-to-edx
11559     59/pop-to-ecx
11560     58/pop-to-eax
11561     # . epilogue
11562     89/<- %esp 5/r32/ebp
11563     5d/pop-to-ebp
11564     c3/return
11565 
11566 new-literal:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
11567     # . prologue
11568     55/push-ebp
11569     89/<- %ebp 4/r32/esp
11570     # . save registers
11571     50/push-eax
11572     51/push-ecx
11573     # var s/ecx: (handle array byte)
11574     68/push 0/imm32
11575     68/push 0/imm32
11576     89/<- %ecx 4/r32/esp
11577     # s = slice-to-string(name)
11578     (slice-to-string Heap *(ebp+0xc) %ecx)
11579     # allocate to out
11580     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
11581     # var out-addr/ecx: (addr var) = lookup(*out)
11582     8b/-> *(ebp+0x10) 1/r32/ecx
11583     (lookup *ecx *(ecx+4))  # => eax
11584     89/<- %ecx 0/r32/eax
11585     # out-addr->block-depth = *Curr-block-depth
11586     8b/-> *Curr-block-depth 0/r32/eax
11587     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
11588     # out-addr->type/eax = new type
11589     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
11590     (allocate *(ebp+8) *Type-tree-size %eax)
11591     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
11592     # nothing else to do; default type is 'literal'
11593     c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
11594 $new-literal:end:
11595     # . reclaim locals
11596     81 0/subop/add %esp 8/imm32
11597     # . restore registers
11598     59/pop-to-ecx
11599     58/pop-to-eax
11600     # . epilogue
11601     89/<- %esp 5/r32/ebp
11602     5d/pop-to-ebp
11603     c3/return
11604 
11605 new-var-from-slice:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
11606     # . prologue
11607     55/push-ebp
11608     89/<- %ebp 4/r32/esp
11609     # . save registers
11610     51/push-ecx
11611     # var tmp/ecx: (handle array byte)
11612     68/push 0/imm32
11613     68/push 0/imm32
11614     89/<- %ecx 4/r32/esp
11615     # tmp = slice-to-string(name)
11616     (slice-to-string Heap *(ebp+0xc) %ecx)
11617     # out = new-var(tmp)
11618     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
11619 $new-var-from-slice:end:
11620     # . reclaim locals
11621     81 0/subop/add %esp 8/imm32
11622     # . restore registers
11623     59/pop-to-ecx
11624     # . epilogue
11625     89/<- %esp 5/r32/ebp
11626     5d/pop-to-ebp
11627     c3/return
11628 
11629 new-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
11630     # . prologue
11631     55/push-ebp
11632     89/<- %ebp 4/r32/esp
11633     # . save registers
11634     50/push-eax
11635     51/push-ecx
11636     #
11637     (allocate *(ebp+8) *Stmt-size *(ebp+0x14))
11638     # var out-addr/eax: (addr stmt) = lookup(*out)
11639     8b/-> *(ebp+0x14) 0/r32/eax
11640     (lookup *eax *(eax+4))  # => eax
11641     # out-addr->tag = stmt
11642     c7 0/subop/copy *eax 2/imm32/tag/var-on-stack  # Stmt-tag
11643     # result->var = var
11644     8b/-> *(ebp+0xc) 1/r32/ecx
11645     89/<- *(eax+4) 1/r32/ecx  # Vardef-var
11646     8b/-> *(ebp+0x10) 1/r32/ecx
11647     89/<- *(eax+8) 1/r32/ecx  # Vardef-var
11648 $new-var-def:end:
11649     # . restore registers
11650     59/pop-to-ecx
11651     58/pop-to-eax
11652     # . epilogue
11653     89/<- %esp 5/r32/ebp
11654     5d/pop-to-ebp
11655     c3/return
11656 
11657 new-reg-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
11658     # . prologue
11659     55/push-ebp
11660     89/<- %ebp 4/r32/esp
11661     # . save registers
11662     50/push-eax
11663     # eax = out
11664     8b/-> *(ebp+0x14) 0/r32/eax
11665     #
11666     (allocate *(ebp+8) *Stmt-size %eax)
11667     # var out-addr/eax: (addr stmt) = lookup(*out)
11668     (lookup *eax *(eax+4))  # => eax
11669     # set tag
11670     c7 0/subop/copy *eax 3/imm32/tag/var-in-register  # Stmt-tag
11671     # set output
11672     8d/copy-address *(eax+0x14) 0/r32/eax  # Regvardef-outputs
11673     (append-stmt-var Heap  *(ebp+0xc) *(ebp+0x10)  0 0  0  %eax)
11674 $new-reg-var-def:end:
11675     # . restore registers
11676     58/pop-to-eax
11677     # . epilogue
11678     89/<- %esp 5/r32/ebp
11679     5d/pop-to-ebp
11680     c3/return
11681 
11682 append-list:  # ad: (addr allocation-descriptor), value: (handle _type), list: (handle list _type), out: (addr handle list _type)
11683     # . prologue
11684     55/push-ebp
11685     89/<- %ebp 4/r32/esp
11686     # . save registers
11687     50/push-eax
11688     51/push-ecx
11689     57/push-edi
11690     # edi = out
11691     8b/-> *(ebp+0x1c) 7/r32/edi
11692     # *out = new list
11693     (allocate *(ebp+8) *List-size %edi)
11694     # var out-addr/edi: (addr list _type) = lookup(*out)
11695     (lookup *edi *(edi+4))  # => eax
11696     89/<- %edi 0/r32/eax
11697     # out-addr->value = value
11698     8b/-> *(ebp+0xc) 0/r32/eax
11699     89/<- *edi 0/r32/eax  # List-value
11700     8b/-> *(ebp+0x10) 0/r32/eax
11701     89/<- *(edi+4) 0/r32/eax  # List-value
11702     # if (list == null) return
11703     81 7/subop/compare *(ebp+0x14) 0/imm32
11704     74/jump-if-= $append-list:end/disp8
11705     # otherwise append
11706 $append-list:non-empty-list:
11707     # var curr/eax: (addr list _type) = lookup(list)
11708     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
11709     # while (curr->next != null) curr = curr->next
11710     {
11711       81 7/subop/compare *(eax+8) 0/imm32  # List-next
11712       74/jump-if-= break/disp8
11713       # curr = lookup(curr->next)
11714       (lookup *(eax+8) *(eax+0xc))  # List-next, List-next => eax
11715       #
11716       eb/jump loop/disp8
11717     }
11718     # edi = out
11719     8b/-> *(ebp+0x1c) 7/r32/edi
11720     # curr->next = out
11721     8b/-> *edi 1/r32/ecx
11722     89/<- *(eax+8) 1/r32/ecx  # List-next
11723     8b/-> *(edi+4) 1/r32/ecx
11724     89/<- *(eax+0xc) 1/r32/ecx  # List-next
11725     # out = list
11726     8b/-> *(ebp+0x14) 1/r32/ecx
11727     89/<- *edi 1/r32/ecx
11728     8b/-> *(ebp+0x18) 1/r32/ecx
11729     89/<- *(edi+4) 1/r32/ecx
11730 $append-list:end:
11731     # . restore registers
11732     5f/pop-to-edi
11733     59/pop-to-ecx
11734     58/pop-to-eax
11735     # . epilogue
11736     89/<- %esp 5/r32/ebp
11737     5d/pop-to-ebp
11738     c3/return
11739 
11740 append-stmt-var:  # ad: (addr allocation-descriptor), v: (handle var), vars: (handle stmt-var), is-deref?: boolean, out: (addr handle stmt-var)
11741     # . prologue
11742     55/push-ebp
11743     89/<- %ebp 4/r32/esp
11744     # . save registers
11745     50/push-eax
11746     51/push-ecx
11747     57/push-edi
11748     # edi = out
11749     8b/-> *(ebp+0x20) 7/r32/edi
11750     # out = new stmt-var
11751     (allocate *(ebp+8) *Stmt-var-size %edi)
11752     # var out-addr/ecx: (addr stmt-var) = lookup(*out)
11753     (lookup *edi *(edi+4))  # => eax
11754     89/<- %ecx 0/r32/eax
11755     # out-addr->value = v
11756     8b/-> *(ebp+0xc) 0/r32/eax
11757     89/<- *ecx 0/r32/eax  # Stmt-var-value
11758     8b/-> *(ebp+0x10) 0/r32/eax
11759     89/<- *(ecx+4) 0/r32/eax  # Stmt-var-value
11760     # out-addr->is-deref? = is-deref?
11761     8b/-> *(ebp+0x1c) 0/r32/eax
11762     89/<- *(ecx+0x10) 0/r32/eax  # Stmt-var-is-deref
11763     # if (vars == null) return result
11764     81 7/subop/compare *(ebp+0x14) 0/imm32/null
11765     74/jump-if-= $append-stmt-var:end/disp8
11766     # otherwise append
11767     # var curr/eax: (addr stmt-var) = lookup(vars)
11768     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
11769     # while (curr->next != null) curr = curr->next
11770     {
11771       81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
11772       74/jump-if-= break/disp8
11773       # curr = lookup(curr->next)
11774       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next, Stmt-var-next => eax
11775       #
11776       eb/jump loop/disp8
11777     }
11778     # curr->next = out
11779     8b/-> *edi 1/r32/ecx
11780     89/<- *(eax+8) 1/r32/ecx  # Stmt-var-next
11781     8b/-> *(edi+4) 1/r32/ecx
11782     89/<- *(eax+0xc) 1/r32/ecx  # Stmt-var-next
11783     # out = vars
11784     8b/-> *(ebp+0x14) 1/r32/ecx
11785     89/<- *edi 1/r32/ecx
11786     8b/-> *(ebp+0x18) 1/r32/ecx
11787     89/<- *(edi+4) 1/r32/ecx
11788 $append-stmt-var:end:
11789     # . restore registers
11790     5f/pop-to-edi
11791     59/pop-to-ecx
11792     58/pop-to-eax
11793     # . epilogue
11794     89/<- %esp 5/r32/ebp
11795     5d/pop-to-ebp
11796     c3/return
11797 
11798 append-to-block:  # ad: (addr allocation-descriptor), block: (addr block), x: (handle stmt)
11799     # . prologue
11800     55/push-ebp
11801     89/<- %ebp 4/r32/esp
11802     # . save registers
11803     50/push-eax
11804     56/push-esi
11805     # esi = block
11806     8b/-> *(ebp+0xc) 6/r32/esi
11807     # block->stmts = append(x, block->stmts)
11808     8d/copy-address *(esi+4) 0/r32/eax  # Block-stmts
11809     (append-list *(ebp+8)  *(ebp+0x10) *(ebp+0x14)  *(esi+4) *(esi+8)  %eax)  # ad, x, x, Block-stmts, Block-stmts
11810 $append-to-block:end:
11811     # . restore registers
11812     5e/pop-to-esi
11813     58/pop-to-eax
11814     # . epilogue
11815     89/<- %esp 5/r32/ebp
11816     5d/pop-to-ebp
11817     c3/return
11818 
11819 ## Parsing types
11820 # We need to create metadata on user-defined types, and we need to use this
11821 # metadata as we parse instructions.
11822 # However, we also want to allow types to be used before their definitions.
11823 # This means we can't ever assume any type data structures exist.
11824 
11825 lookup-or-create-constant:  # container: (addr stmt-var), field-name: (addr slice), out: (addr handle var)
11826     # . prologue
11827     55/push-ebp
11828     89/<- %ebp 4/r32/esp
11829     # . save registers
11830     50/push-eax
11831     56/push-esi
11832     # var container-type/esi: type-id
11833     (container-type *(ebp+8))  # => eax
11834     89/<- %esi 0/r32/eax
11835     # var tmp/eax: (handle typeinfo) = find-or-create-typeinfo(container-type)
11836     68/push 0/imm32
11837     68/push 0/imm32
11838     89/<- %eax 4/r32/esp
11839     (find-or-create-typeinfo %esi %eax)
11840     # var tmp-addr/eax: (addr typeinfo) = lookup(tmp)
11841     (lookup *eax *(eax+4))  # => eax
11842     # result = find-or-create-typeinfo-output-var(typeinfo, field-name)
11843 #?     (write-buffered Stderr "constant: ")
11844 #?     (write-slice-buffered Stderr *(ebp+0xc))
11845 #?     (write-buffered Stderr Newline)
11846 #?     (flush Stderr)
11847     (find-or-create-typeinfo-output-var %eax *(ebp+0xc) *(ebp+0x10))
11848 #?     8b/-> *(ebp+0x10) 0/r32/eax
11849 #?     (write-buffered Stderr "@")
11850 #?     (lookup *eax *(eax+4))
11851 #?     (write-int32-hex-buffered Stderr %eax)
11852 #?     (lookup *eax *(eax+4))
11853 #?     (write-buffered Stderr %eax)
11854 #?     (write-buffered Stderr Newline)
11855 #?     (flush Stderr)
11856 #?     (write-buffered Stderr "offset: ")
11857 #?     8b/-> *(eax+0x14) 0/r32/eax
11858 #?     (write-int32-hex-buffered Stderr %eax)
11859 #?     (write-buffered Stderr Newline)
11860 #?     (flush Stderr)
11861 $lookup-or-create-constant:end:
11862     # . reclaim locals
11863     81 0/subop/add %esp 8/imm32
11864     # . restore registers
11865     5e/pop-to-esi
11866     58/pop-to-eax
11867     # . epilogue
11868     89/<- %esp 5/r32/ebp
11869     5d/pop-to-ebp
11870     c3/return
11871 
11872 # if addr var:
11873 #   container->var->type->right->left->value
11874 # otherwise
11875 #   container->var->type->value
11876 container-type:  # container: (addr stmt-var) -> result/eax: type-id
11877     # . prologue
11878     55/push-ebp
11879     89/<- %ebp 4/r32/esp
11880     #
11881     8b/-> *(ebp+8) 0/r32/eax
11882     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11883     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11884     {
11885       81 7/subop/compare *(eax+8) 0/imm32  # Type-tree-right
11886       74/jump-if-= break/disp8
11887       (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
11888       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
11889     }
11890     8b/-> *(eax+4) 0/r32/eax  # Type-tree-value
11891 $container-type:end:
11892     # . epilogue
11893     89/<- %esp 5/r32/ebp
11894     5d/pop-to-ebp
11895     c3/return
11896 
11897 is-container?:  # t: type-id -> result/eax: boolean
11898     # . prologue
11899     55/push-ebp
11900     89/<- %ebp 4/r32/esp
11901     #
11902     8b/-> *(ebp+8) 0/r32/eax
11903     c1/shift 4/subop/left %eax 2/imm8
11904     3b/compare 0/r32/eax *Primitive-type-ids
11905     0f 9d/set-if->= %al
11906     81 4/subop/and %eax 0xff/imm32
11907 $is-container?:end:
11908     # . epilogue
11909     89/<- %esp 5/r32/ebp
11910     5d/pop-to-ebp
11911     c3/return
11912 
11913 find-or-create-typeinfo:  # t: type-id, out: (addr handle typeinfo)
11914     # . prologue
11915     55/push-ebp
11916     89/<- %ebp 4/r32/esp
11917     # . save registers
11918     50/push-eax
11919     51/push-ecx
11920     52/push-edx
11921     57/push-edi
11922     # edi = out
11923     8b/-> *(ebp+0xc) 7/r32/edi
11924     # var fields/ecx: (handle table (handle array byte) (handle typeinfo-entry))
11925     68/push 0/imm32
11926     68/push 0/imm32
11927     89/<- %ecx 4/r32/esp
11928     # find-typeinfo(t, out)
11929     (find-typeinfo *(ebp+8) %edi)
11930     {
11931       # if (*out != 0) break
11932       81 7/subop/compare *edi 0/imm32
11933       0f 85/jump-if-!= break/disp32
11934 $find-or-create-typeinfo:create:
11935       # *out = allocate
11936       (allocate Heap *Typeinfo-size %edi)
11937       # var tmp/eax: (addr typeinfo) = lookup(*out)
11938       (lookup *edi *(edi+4))  # => eax
11939 #?     (write-buffered Stderr "created typeinfo at ")
11940 #?     (write-int32-hex-buffered Stderr %eax)
11941 #?     (write-buffered Stderr " for type-id ")
11942 #?     (write-int32-hex-buffered Stderr *(ebp+8))
11943 #?     (write-buffered Stderr Newline)
11944 #?     (flush Stderr)
11945       # tmp->id = t
11946       8b/-> *(ebp+8) 2/r32/edx
11947       89/<- *eax 2/r32/edx  # Typeinfo-id
11948       # tmp->fields = new table
11949       # . fields = new table
11950       (new-stream Heap 0x40 *Typeinfo-fields-row-size %ecx)
11951       # . tmp->fields = fields
11952       8b/-> *ecx 2/r32/edx
11953       89/<- *(eax+4) 2/r32/edx  # Typeinfo-fields
11954       8b/-> *(ecx+4) 2/r32/edx
11955       89/<- *(eax+8) 2/r32/edx  # Typeinfo-fields
11956       # tmp->next = Program->types
11957       8b/-> *_Program-types 1/r32/ecx
11958       89/<- *(eax+0x10) 1/r32/ecx  # Typeinfo-next
11959       8b/-> *_Program-types->payload 1/r32/ecx
11960       89/<- *(eax+0x14) 1/r32/ecx  # Typeinfo-next
11961       # Program->types = out
11962       8b/-> *edi 1/r32/ecx
11963       89/<- *_Program-types 1/r32/ecx
11964       8b/-> *(edi+4) 1/r32/ecx
11965       89/<- *_Program-types->payload 1/r32/ecx
11966     }
11967 $find-or-create-typeinfo:end:
11968     # . reclaim locals
11969     81 0/subop/add %esp 8/imm32
11970     # . restore registers
11971     5f/pop-to-edi
11972     5a/pop-to-edx
11973     59/pop-to-ecx
11974     58/pop-to-eax
11975     # . epilogue
11976     89/<- %esp 5/r32/ebp
11977     5d/pop-to-ebp
11978     c3/return
11979 
11980 find-typeinfo:  # t: type-id, out: (addr handle typeinfo)
11981     # . prologue
11982     55/push-ebp
11983     89/<- %ebp 4/r32/esp
11984     # . save registers
11985     50/push-eax
11986     51/push-ecx
11987     52/push-edx
11988     57/push-edi
11989     # ecx = t
11990     8b/-> *(ebp+8) 1/r32/ecx
11991     # edi = out
11992     8b/-> *(ebp+0xc) 7/r32/edi
11993     # *out = Program->types
11994     8b/-> *_Program-types 0/r32/eax
11995     89/<- *edi 0/r32/eax
11996     8b/-> *_Program-types->payload 0/r32/eax
11997     89/<- *(edi+4) 0/r32/eax
11998     {
11999 $find-typeinfo:loop:
12000       # if (*out == 0) break
12001       81 7/subop/compare *edi 0/imm32
12002       74/jump-if-= break/disp8
12003 $find-typeinfo:check:
12004       # var tmp/eax: (addr typeinfo) = lookup(*out)
12005       (lookup *edi *(edi+4))  # => eax
12006       # if (tmp->id == t) break
12007       39/compare *eax 1/r32/ecx  # Typeinfo-id
12008       74/jump-if-= break/disp8
12009 $find-typeinfo:continue:
12010       # *out = tmp->next
12011       8b/-> *(eax+0x10) 2/r32/edx  # Typeinfo-next
12012       89/<- *edi 2/r32/edx
12013       8b/-> *(eax+0x14) 2/r32/edx  # Typeinfo-next
12014       89/<- *(edi+4) 2/r32/edx
12015       #
12016       eb/jump loop/disp8
12017     }
12018 $find-typeinfo:end:
12019     # . restore registers
12020     5f/pop-to-edi
12021     5a/pop-to-edx
12022     59/pop-to-ecx
12023     58/pop-to-eax
12024     # . epilogue
12025     89/<- %esp 5/r32/ebp
12026     5d/pop-to-ebp
12027     c3/return
12028 
12029 find-or-create-typeinfo-output-var:  # T: (addr typeinfo), f: (addr slice), out: (addr handle var)
12030     # . prologue
12031     55/push-ebp
12032     89/<- %ebp 4/r32/esp
12033     # . save registers
12034     50/push-eax
12035     52/push-edx
12036     57/push-edi
12037     # var dest/edi: (handle typeinfo-entry)
12038     68/push 0/imm32
12039     68/push 0/imm32
12040     89/<- %edi 4/r32/esp
12041     # find-or-create-typeinfo-fields(T, f, dest)
12042     (find-or-create-typeinfo-fields *(ebp+8) *(ebp+0xc) %edi)
12043     # var dest-addr/edi: (addr typeinfo-entry) = lookup(dest)
12044     (lookup *edi *(edi+4))  # => eax
12045     89/<- %edi 0/r32/eax
12046     # if dest-addr->output-var doesn't exist, create it
12047     {
12048       81 7/subop/compare *(edi+0xc) 0/imm32  # Typeinfo-entry-output-var
12049       0f 85/jump-if-!= break/disp32
12050       # dest-addr->output-var = new var(dummy name, type, -1 offset)
12051       # . var name/eax: (handle array byte) = "field"
12052       68/push 0/imm32
12053       68/push 0/imm32
12054       89/<- %eax 4/r32/esp
12055       (slice-to-string Heap *(ebp+0xc) %eax)
12056       # . new var
12057       8d/copy-address *(edi+0xc) 2/r32/edx
12058       (new-var Heap  *eax *(eax+4)  %edx)
12059       # . reclaim name
12060       81 0/subop/add %esp 8/imm32
12061       # var result/edx: (addr var) = lookup(dest-addr->output-var)
12062       (lookup *(edi+0xc) *(edi+0x10))  # => eax
12063       89/<- %edx 0/r32/eax
12064       # result->type = new constant type
12065       8d/copy-address *(edx+8) 0/r32/eax  # Var-type
12066       (allocate Heap *Type-tree-size %eax)
12067       (lookup *(edx+8) *(edx+0xc))  # => eax
12068       c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
12069       c7 0/subop/copy *(eax+4) 6/imm32/constant  # Type-tree-value
12070       c7 0/subop/copy *(eax+8) 0/imm32  # Type-tree-left
12071       c7 0/subop/copy *(eax+0xc) 0/imm32  # Type-tree-right
12072       c7 0/subop/copy *(eax+0x10) 0/imm32  # Type-tree-right
12073       # result->offset isn't filled out yet
12074       c7 0/subop/copy *(edx+0x14) -1/imm32/uninitialized  # Var-offset
12075     }
12076     # out = dest-addr->output-var
12077     8b/-> *(ebp+0x10) 2/r32/edx
12078     8b/-> *(edi+0xc) 0/r32/eax  # Typeinfo-entry-output-var
12079     89/<- *edx 0/r32/eax
12080     8b/-> *(edi+0x10) 0/r32/eax  # Typeinfo-entry-output-var
12081     89/<- *(edx+4) 0/r32/eax
12082 $find-or-create-typeinfo-output-var:end:
12083     # . reclaim locals
12084     81 0/subop/add %esp 8/imm32
12085     # . restore registers
12086     5f/pop-to-edi
12087     5a/pop-to-edx
12088     58/pop-to-eax
12089     # . epilogue
12090     89/<- %esp 5/r32/ebp
12091     5d/pop-to-ebp
12092     c3/return
12093 
12094 find-or-create-typeinfo-fields:  # T: (addr typeinfo), f: (addr slice), out: (addr handle typeinfo-entry)
12095     # . prologue
12096     55/push-ebp
12097     89/<- %ebp 4/r32/esp
12098     # . save registers
12099     50/push-eax
12100     56/push-esi
12101     57/push-edi
12102     # eax = lookup(T->fields)
12103     8b/-> *(ebp+8) 0/r32/eax
12104     (lookup *(eax+4) *(eax+8))  # Typeinfo-fields Typeinfo-fields => eax
12105     # edi = out
12106     8b/-> *(ebp+0x10) 7/r32/edi
12107     # var src/esi: (addr handle typeinfo-entry) = get-or-insert-slice(T->fields, f)
12108     (get-or-insert-slice %eax *(ebp+0xc) *Typeinfo-fields-row-size Heap)  # => eax
12109     89/<- %esi 0/r32/eax
12110     # if src doesn't exist, allocate it
12111     {
12112       81 7/subop/compare *esi 0/imm32
12113       75/jump-if-!= break/disp8
12114       (allocate Heap *Typeinfo-entry-size %esi)
12115 #?       (write-buffered Stderr "handle at ")
12116 #?       (write-int32-hex-buffered Stderr %esi)
12117 #?       (write-buffered Stderr ": ")
12118 #?       (write-int32-hex-buffered Stderr *esi)
12119 #?       (write-buffered Stderr " ")
12120 #?       (write-int32-hex-buffered Stderr *(esi+4))
12121 #?       (write-buffered Stderr Newline)
12122 #?       (flush Stderr)
12123 #?       (lookup *esi *(esi+4))
12124 #?       (write-buffered Stderr "created typeinfo fields at ")
12125 #?       (write-int32-hex-buffered Stderr %esi)
12126 #?       (write-buffered Stderr " for ")
12127 #?       (write-int32-hex-buffered Stderr *(ebp+8))
12128 #?       (write-buffered Stderr Newline)
12129 #?       (flush Stderr)
12130     }
12131     # *out = src
12132     # . *edi = *src
12133     8b/-> *esi 0/r32/eax
12134     89/<- *edi 0/r32/eax
12135     8b/-> *(esi+4) 0/r32/eax
12136     89/<- *(edi+4) 0/r32/eax
12137 $find-or-create-typeinfo-fields:end:
12138     # . restore registers
12139     5f/pop-to-edi
12140     5e/pop-to-esi
12141     58/pop-to-eax
12142     # . epilogue
12143     89/<- %esp 5/r32/ebp
12144     5d/pop-to-ebp
12145     c3/return
12146 
12147 populate-mu-type:  # in: (addr stream byte), t: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
12148     # pseudocode:
12149     #   var line: (stream byte 512)
12150     #   curr-index = 0
12151     #   while true
12152     #     clear-stream(line)
12153     #     read-line-buffered(in, line)
12154     #     if line->write == 0
12155     #       abort
12156     #     word-slice = next-mu-token(line)
12157     #     if slice-empty?(word-slice)               # end of line
12158     #       continue
12159     #     if slice-equal?(word-slice, "}")
12160     #       break
12161     #     var v: (handle var) = parse-var-with-type(word-slice, line)
12162     #     var r: (handle typeinfo-fields) = find-or-create-typeinfo-fields(t, word-slice/v->name)
12163     #     TODO: ensure that r->first is null
12164     #     r->index = curr-index
12165     #     curr-index++
12166     #     r->input-var = v
12167     #     if r->output-var == 0
12168     #       r->output-var = new literal
12169     #     TODO: ensure nothing else in line
12170     # t->total-size-in-bytes = -2 (not yet initialized)
12171     #
12172     # . prologue
12173     55/push-ebp
12174     89/<- %ebp 4/r32/esp
12175     # var curr-index: int at *(ebp-4)
12176     68/push 0/imm32
12177     # . save registers
12178     50/push-eax
12179     51/push-ecx
12180     52/push-edx
12181     53/push-ebx
12182     56/push-esi
12183     57/push-edi
12184     # edi = t
12185     8b/-> *(ebp+0xc) 7/r32/edi
12186     # var line/ecx: (stream byte 512)
12187     81 5/subop/subtract %esp 0x200/imm32
12188     68/push 0x200/imm32/size
12189     68/push 0/imm32/read
12190     68/push 0/imm32/write
12191     89/<- %ecx 4/r32/esp
12192     # var word-slice/edx: slice
12193     68/push 0/imm32/end
12194     68/push 0/imm32/start
12195     89/<- %edx 4/r32/esp
12196     # var v/esi: (handle var)
12197     68/push 0/imm32
12198     68/push 0/imm32
12199     89/<- %esi 4/r32/esp
12200     # var r/ebx: (handle typeinfo-entry)
12201     68/push 0/imm32
12202     68/push 0/imm32
12203     89/<- %ebx 4/r32/esp
12204     {
12205 $populate-mu-type:line-loop:
12206       (clear-stream %ecx)
12207       (read-line-buffered *(ebp+8) %ecx)
12208       # if (line->write == 0) abort
12209       81 7/subop/compare *ecx 0/imm32
12210       0f 84/jump-if-= $populate-mu-type:error1/disp32
12211 +--  6 lines: #?       # dump line ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
12217       (next-mu-token %ecx %edx)
12218       # if slice-empty?(word-slice) continue
12219       (slice-empty? %edx)  # => eax
12220       3d/compare-eax-and 0/imm32
12221       0f 85/jump-if-!= loop/disp32
12222       # if slice-equal?(word-slice, "}") break
12223       (slice-equal? %edx "}")
12224       3d/compare-eax-and 0/imm32
12225       0f 85/jump-if-!= break/disp32
12226 $populate-mu-type:parse-element:
12227       # v = parse-var-with-type(word-slice, first-line)
12228       # must do this first to strip the trailing ':' from word-slice before
12229       # using it in find-or-create-typeinfo-fields below
12230       # TODO: clean up that mutation in parse-var-with-type
12231       (parse-var-with-type %edx %ecx %esi *(ebp+0x10) *(ebp+0x14))
12232       # if v is an addr, abort
12233       (lookup *esi *(esi+4))  # => eax
12234       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12235       (is-mu-addr-type? %eax)  # => eax
12236       3d/compare-eax-and 0/imm32/false
12237       0f 85/jump-if-!= $populate-mu-type:error2/disp32
12238       # if v is an array, abort  (we could support it, but initialization gets complex)
12239       (lookup *esi *(esi+4))  # => eax
12240       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12241       (is-mu-array-type? %eax)  # => eax
12242       3d/compare-eax-and 0/imm32/false
12243       0f 85/jump-if-!= $populate-mu-type:error3/disp32
12244       # if v is a byte, abort
12245       (lookup *esi *(esi+4))  # => eax
12246       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12247       (is-simple-mu-type? %eax 8)  # byte => eax
12248       3d/compare-eax-and 0/imm32/false
12249       0f 85/jump-if-!= $populate-mu-type:error4/disp32
12250       # if v is a slice, abort
12251       (lookup *esi *(esi+4))  # => eax
12252       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12253       (is-simple-mu-type? %eax 0xc)  # slice => eax
12254       3d/compare-eax-and 0/imm32/false
12255       0f 85/jump-if-!= $populate-mu-type:error5/disp32
12256       # if v is a stream, abort  (we could support it, but initialization gets even more complex)
12257       (lookup *esi *(esi+4))  # => eax
12258       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12259       (is-mu-stream-type? %eax)  # => eax
12260       3d/compare-eax-and 0/imm32/false
12261       0f 85/jump-if-!= $populate-mu-type:error6/disp32
12262       # var tmp/ecx
12263       51/push-ecx
12264 $populate-mu-type:create-typeinfo-fields:
12265       # var r/ebx: (handle typeinfo-entry)
12266       (find-or-create-typeinfo-fields %edi %edx %ebx)
12267       # r->index = curr-index
12268       (lookup *ebx *(ebx+4))  # => eax
12269       8b/-> *(ebp-4) 1/r32/ecx
12270 #?       (write-buffered Stderr "saving index ")
12271 #?       (write-int32-hex-buffered Stderr %ecx)
12272 #?       (write-buffered Stderr " at ")
12273 #?       (write-int32-hex-buffered Stderr %edi)
12274 #?       (write-buffered Stderr Newline)
12275 #?       (flush Stderr)
12276       89/<- *(eax+8) 1/r32/ecx  # Typeinfo-entry-index
12277       # ++curr-index
12278       ff 0/subop/increment *(ebp-4)
12279 $populate-mu-type:set-input-type:
12280       # r->input-var = v
12281       8b/-> *esi 1/r32/ecx
12282       89/<- *eax 1/r32/ecx  # Typeinfo-entry-input-var
12283       8b/-> *(esi+4) 1/r32/ecx
12284       89/<- *(eax+4) 1/r32/ecx  # Typeinfo-entry-input-var
12285       # restore line
12286       59/pop-to-ecx
12287       {
12288 $populate-mu-type:create-output-type:
12289         # if (r->output-var == 0) create a new var with some placeholder data
12290         81 7/subop/compare *(eax+0xc) 0/imm32  # Typeinfo-entry-output-var
12291         75/jump-if-!= break/disp8
12292         8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
12293         (new-literal Heap %edx %eax)
12294       }
12295       e9/jump loop/disp32
12296     }
12297 $populate-mu-type:invalidate-total-size-in-bytes:
12298     # Offsets and total size may not be accurate here since we may not yet
12299     # have encountered the element types.
12300     # We'll recompute them separately after parsing the entire program.
12301     c7 0/subop/copy *(edi+0xc) -2/imm32/uninitialized  # Typeinfo-total-size-in-bytes
12302 $populate-mu-type:end:
12303     # . reclaim locals
12304     81 0/subop/add %esp 0x224/imm32
12305     # . restore registers
12306     5f/pop-to-edi
12307     5e/pop-to-esi
12308     5b/pop-to-ebx
12309     5a/pop-to-edx
12310     59/pop-to-ecx
12311     58/pop-to-eax
12312     # reclaim curr-index
12313     81 0/subop/add %esp 4/imm32
12314     # . epilogue
12315     89/<- %esp 5/r32/ebp
12316     5d/pop-to-ebp
12317     c3/return
12318 
12319 $populate-mu-type:error1:
12320     # error("incomplete type definition '" t->name "'\n")
12321     (write-buffered *(ebp+0x10) "incomplete type definition '")
12322     (type-name *edi)  # Typeinfo-id => eax
12323     (write-buffered *(ebp+0x10) %eax)
12324     (write-buffered *(ebp+0x10) "\n")
12325     (flush *(ebp+0x10))
12326     (stop *(ebp+0x14) 1)
12327     # never gets here
12328 
12329 $populate-mu-type:error2:
12330     (write-buffered *(ebp+0x10) "type ")
12331     (type-name *edi)  # Typeinfo-id => eax
12332     (write-buffered *(ebp+0x10) %eax)
12333     (write-buffered *(ebp+0x10) ": 'addr' elements not allowed\n")
12334     (flush *(ebp+0x10))
12335     (stop *(ebp+0x14) 1)
12336     # never gets here
12337 
12338 $populate-mu-type:error3:
12339     (write-buffered *(ebp+0x10) "type ")
12340     (type-name *edi)  # Typeinfo-id => eax
12341     (write-buffered *(ebp+0x10) %eax)
12342     (write-buffered *(ebp+0x10) ": 'array' elements not allowed for now\n")
12343     (flush *(ebp+0x10))
12344     (stop *(ebp+0x14) 1)
12345     # never gets here
12346 
12347 $populate-mu-type:error4:
12348     (write-buffered *(ebp+0x10) "type ")
12349     (type-name *edi)  # Typeinfo-id => eax
12350     (write-buffered *(ebp+0x10) %eax)
12351     (write-buffered *(ebp+0x10) ": 'byte' elements not allowed\n")
12352     (flush *(ebp+0x10))
12353     (stop *(ebp+0x14) 1)
12354     # never gets here
12355 
12356 $populate-mu-type:error5:
12357     (write-buffered *(ebp+0x10) "type ")
12358     (type-name *edi)  # Typeinfo-id => eax
12359     (write-buffered *(ebp+0x10) %eax)
12360     (write-buffered *(ebp+0x10) ": 'slice' elements not allowed\n")
12361     (flush *(ebp+0x10))
12362     (stop *(ebp+0x14) 1)
12363     # never gets here
12364 
12365 $populate-mu-type:error6:
12366     (write-buffered *(ebp+0x10) "type ")
12367     (type-name *edi)  # Typeinfo-id => eax
12368     (write-buffered *(ebp+0x10) %eax)
12369     (write-buffered *(ebp+0x10) ": 'stream' elements not allowed for now\n")
12370     (flush *(ebp+0x10))
12371     (stop *(ebp+0x14) 1)
12372     # never gets here
12373 
12374 type-name:  # index: int -> result/eax: (addr array byte)
12375     # . prologue
12376     55/push-ebp
12377     89/<- %ebp 4/r32/esp
12378     #
12379     (index Type-id *(ebp+8))
12380 $type-name:end:
12381     # . epilogue
12382     89/<- %esp 5/r32/ebp
12383     5d/pop-to-ebp
12384     c3/return
12385 
12386 index:  # arr: (addr stream (handle array byte)), index: int -> result/eax: (addr array byte)
12387     # . prologue
12388     55/push-ebp
12389     89/<- %ebp 4/r32/esp
12390     # . save registers
12391     56/push-esi
12392     # TODO: bounds-check index
12393     # esi = arr
12394     8b/-> *(ebp+8) 6/r32/esi
12395     # eax = index
12396     8b/-> *(ebp+0xc) 0/r32/eax
12397     # eax = *(arr + 12 + index)
12398     8b/-> *(esi+eax<<2+0xc) 0/r32/eax
12399 $index:end:
12400     # . restore registers
12401     5e/pop-to-esi
12402     # . epilogue
12403     89/<- %esp 5/r32/ebp
12404     5d/pop-to-ebp
12405     c3/return
12406 
12407 #######################################################
12408 # Compute type sizes
12409 #######################################################
12410 
12411 # Compute the sizes of all user-defined types.
12412 # We'll need the sizes of their elements, which may be other user-defined
12413 # types, which we will compute as needed.
12414 
12415 # Initially, all user-defined types have their sizes set to -2 (invalid)
12416 populate-mu-type-sizes:  # err: (addr buffered-file), ed: (addr exit-descriptor)
12417     # . prologue
12418     55/push-ebp
12419     89/<- %ebp 4/r32/esp
12420 $populate-mu-type-sizes:total-sizes:
12421     # var curr/eax: (addr typeinfo) = lookup(Program->types)
12422     (lookup *_Program-types *_Program-types->payload)  # => eax
12423     {
12424       # if (curr == null) break
12425       3d/compare-eax-and 0/imm32/null
12426       74/jump-if-= break/disp8
12427       (populate-mu-type-sizes-in-type %eax *(ebp+8) *(ebp+0xc))
12428       # curr = lookup(curr->next)
12429       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
12430       eb/jump loop/disp8
12431     }
12432 $populate-mu-type-sizes:offsets:
12433     # curr = *Program->types
12434     (lookup *_Program-types *_Program-types->payload)  # => eax
12435     {
12436       # if (curr == null) break
12437       3d/compare-eax-and 0/imm32/null
12438       74/jump-if-= break/disp8
12439       (populate-mu-type-offsets %eax *(ebp+8) *(ebp+0xc))
12440       # curr = curr->next
12441       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
12442       eb/jump loop/disp8
12443     }
12444 $populate-mu-type-sizes:end:
12445     # . epilogue
12446     89/<- %esp 5/r32/ebp
12447     5d/pop-to-ebp
12448     c3/return
12449 
12450 # compute sizes of all fields, recursing as necessary
12451 # sum up all their sizes to arrive at total size
12452 # fields may be out of order, but that doesn't affect the answer
12453 populate-mu-type-sizes-in-type:  # T: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
12454     # . prologue
12455     55/push-ebp
12456     89/<- %ebp 4/r32/esp
12457     # . save registers
12458     50/push-eax
12459     51/push-ecx
12460     52/push-edx
12461     56/push-esi
12462     57/push-edi
12463     # esi = T
12464     8b/-> *(ebp+8) 6/r32/esi
12465     # if T is already computed, return
12466     81 7/subop/compare *(esi+0xc) 0/imm32  # Typeinfo-total-size-in-bytes
12467     0f 8d/jump-if->= $populate-mu-type-sizes-in-type:end/disp32
12468     # if T is being computed, abort
12469     81 7/subop/compare *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
12470     0f 84/jump-if-= $populate-mu-type-sizes-in-type:abort/disp32
12471     # tag T (-2 to -1) to avoid infinite recursion
12472     c7 0/subop/copy *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
12473     # var total-size/edi: int = 0
12474     bf/copy-to-edi 0/imm32
12475     # - for every field, if it's a user-defined type, compute its size
12476     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
12477     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
12478     89/<- %ecx 0/r32/eax
12479     # var table-size/edx: int = table->write
12480     8b/-> *ecx 2/r32/edx  # stream-write
12481     # var curr/ecx: (addr table_row) = table->data
12482     8d/copy-address *(ecx+0xc) 1/r32/ecx
12483     # var max/edx: (addr table_row) = table->data + table->write
12484     8d/copy-address *(ecx+edx) 2/r32/edx
12485     {
12486 $populate-mu-type-sizes-in-type:loop:
12487       # if (curr >= max) break
12488       39/compare %ecx 2/r32/edx
12489       73/jump-if-addr>= break/disp8
12490       # var t/eax: (addr typeinfo-entry) = lookup(curr->value)
12491       (lookup *(ecx+8) *(ecx+0xc))  # => eax
12492       # if (t->input-var == 0) silently ignore it; we'll emit a nice error message while type-checking
12493       81 7/subop/compare *eax 0/imm32  # Typeinfo-entry-input-var
12494       74/jump-if-= $populate-mu-type-sizes-in-type:end/disp8
12495       # compute size of t->input-var
12496       (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
12497       (compute-size-of-var %eax *(ebp+0xc) *(ebp+0x10))  # => eax
12498       # result += eax
12499       01/add-to %edi 0/r32/eax
12500       # curr += row-size
12501       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
12502       #
12503       eb/jump loop/disp8
12504     }
12505     # - save result
12506     89/<- *(esi+0xc) 7/r32/edi  # Typeinfo-total-size-in-bytes
12507 $populate-mu-type-sizes-in-type:end:
12508     # . restore registers
12509     5f/pop-to-edi
12510     5e/pop-to-esi
12511     5a/pop-to-edx
12512     59/pop-to-ecx
12513     58/pop-to-eax
12514     # . epilogue
12515     89/<- %esp 5/r32/ebp
12516     5d/pop-to-ebp
12517     c3/return
12518 
12519 $populate-mu-type-sizes-in-type:abort:
12520     (write-buffered *(ebp+0xc) "cycle in type definitions\n")
12521     (flush *(ebp+0xc))
12522     (stop *(ebp+0x10) 1)
12523     # never gets here
12524 
12525 # Analogous to size-of, except we need to compute what size-of can just read
12526 # off the right data structures.
12527 compute-size-of-var:  # in: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
12528     # . prologue
12529     55/push-ebp
12530     89/<- %ebp 4/r32/esp
12531     # . push registers
12532     51/push-ecx
12533     # var t/ecx: (addr type-tree) = lookup(v->type)
12534     8b/-> *(ebp+8) 1/r32/ecx
12535     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
12536     89/<- %ecx 0/r32/eax
12537     # if (t->is-atom == false) t = lookup(t->left)
12538     {
12539       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
12540       75/jump-if-!= break/disp8
12541       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
12542       89/<- %ecx 0/r32/eax
12543     }
12544     # TODO: ensure t is an atom
12545     (compute-size-of-type-id *(ecx+4) *(ebp+0xc) *(ebp+0x10))  # Type-tree-value => eax
12546 $compute-size-of-var:end:
12547     # . restore registers
12548     59/pop-to-ecx
12549     # . epilogue
12550     89/<- %esp 5/r32/ebp
12551     5d/pop-to-ebp
12552     c3/return
12553 
12554 compute-size-of-type-id:  # t: type-id, err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
12555     # . prologue
12556     55/push-ebp
12557     89/<- %ebp 4/r32/esp
12558     # . save registers
12559     51/push-ecx
12560     # var out/ecx: (handle typeinfo)
12561     68/push 0/imm32
12562     68/push 0/imm32
12563     89/<- %ecx 4/r32/esp
12564     # eax = t
12565     8b/-> *(ebp+8) 0/r32/eax
12566     # if t is a literal, return 0
12567     3d/compare-eax-and 0/imm32/literal
12568     0f 84/jump-if-= $compute-size-of-type-id:end/disp32  # eax changes type from type-id to int
12569     # if t is a byte, return 4 (because we don't really support non-multiples of 4)
12570     3d/compare-eax-and 8/imm32/byte
12571     {
12572       75/jump-if-!= break/disp8
12573       b8/copy-to-eax 4/imm32
12574       eb/jump $compute-size-of-type-id:end/disp8
12575     }
12576     # if t is a handle, return 8
12577     3d/compare-eax-and 4/imm32/handle
12578     {
12579       75/jump-if-!= break/disp8
12580       b8/copy-to-eax 8/imm32
12581       eb/jump $compute-size-of-type-id:end/disp8  # eax changes type from type-id to int
12582     }
12583     # if t is a slice, return 8
12584     3d/compare-eax-and 0xc/imm32/slice
12585     {
12586       75/jump-if-!= break/disp8
12587       b8/copy-to-eax 8/imm32
12588       eb/jump $compute-size-of-type-id:end/disp8  # eax changes type from type-id to int
12589     }
12590     # if t is a user-defined type, compute its size
12591     # TODO: support non-atom type
12592     (find-typeinfo %eax %ecx)
12593     {
12594       81 7/subop/compare *ecx 0/imm32
12595       74/jump-if-= break/disp8
12596 $compute-size-of-type-id:user-defined:
12597       (lookup *ecx *(ecx+4))  # => eax
12598       (populate-mu-type-sizes-in-type %eax *(ebp+0xc) *(ebp+0x10))
12599       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
12600       eb/jump $compute-size-of-type-id:end/disp8
12601     }
12602     # otherwise return the word size
12603     b8/copy-to-eax 4/imm32
12604 $compute-size-of-type-id:end:
12605     # . reclaim locals
12606     81 0/subop/add %esp 8/imm32
12607     # . restore registers
12608     59/pop-to-ecx
12609     # . epilogue
12610     89/<- %esp 5/r32/ebp
12611     5d/pop-to-ebp
12612     c3/return
12613 
12614 # at this point we have total sizes for all user-defined types
12615 # compute offsets for each element
12616 # complication: fields may be out of order
12617 populate-mu-type-offsets:  # in: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
12618     # . prologue
12619     55/push-ebp
12620     89/<- %ebp 4/r32/esp
12621     # . save registers
12622     50/push-eax
12623     51/push-ecx
12624     52/push-edx
12625     53/push-ebx
12626     56/push-esi
12627     57/push-edi
12628 #?     (dump-typeinfos "aaa\n")
12629     # var curr-offset/edi: int = 0
12630     bf/copy-to-edi 0/imm32
12631     # var table/ecx: (addr table string_key (handle typeinfo-entry)) = lookup(in->fields)
12632     8b/-> *(ebp+8) 1/r32/ecx
12633     (lookup *(ecx+4) *(ecx+8))  # Typeinfo-fields Typeinfo-fields => eax
12634     89/<- %ecx 0/r32/eax
12635     # var num-elems/edx: int = table->write / Typeinfo-fields-row-size
12636     8b/-> *ecx 2/r32/edx  # stream-write
12637     c1 5/subop/shift-right-logical  %edx 4/imm8
12638     # var i/ebx: int = 0
12639     bb/copy-to-ebx 0/imm32
12640     {
12641 $populate-mu-type-offsets:loop:
12642       39/compare %ebx 2/r32/edx
12643       0f 8d/jump-if->= break/disp32
12644 #?       (write-buffered Stderr "looking up index ")
12645 #?       (write-int32-hex-buffered Stderr %ebx)
12646 #?       (write-buffered Stderr " in ")
12647 #?       (write-int32-hex-buffered Stderr *(ebp+8))
12648 #?       (write-buffered Stderr Newline)
12649 #?       (flush Stderr)
12650       # var v/esi: (addr typeinfo-entry)
12651       (locate-typeinfo-entry-with-index %ecx %ebx *(ebp+0xc) *(ebp+0x10))  # => eax
12652       89/<- %esi 0/r32/eax
12653       # if v is null, silently move on; we'll emit a nice error message while type-checking
12654       81 7/subop/compare %esi 0/imm32  # Typeinfo-entry-input-var
12655       74/jump-if-= $populate-mu-type-offsets:end/disp8
12656       # if (v->input-var == 0) silently ignore v; we'll emit a nice error message while type-checking
12657       81 7/subop/compare *esi 0/imm32  # Typeinfo-entry-input-var
12658       74/jump-if-= $populate-mu-type-offsets:end/disp8
12659       # v->output-var->offset = curr-offset
12660       # . eax: (addr var)
12661       (lookup *(esi+0xc) *(esi+0x10))  # Typeinfo-entry-output-var Typeinfo-entry-output-var => eax
12662       89/<- *(eax+0x14) 7/r32/edi  # Var-offset
12663       # curr-offset += size-of(v->input-var)
12664       (lookup *esi *(esi+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
12665       (size-of %eax)  # => eax
12666       01/add-to %edi 0/r32/eax
12667       # ++i
12668       43/increment-ebx
12669       e9/jump loop/disp32
12670     }
12671 $populate-mu-type-offsets:end:
12672     # . restore registers
12673     5f/pop-to-edi
12674     5e/pop-to-esi
12675     5b/pop-to-ebx
12676     5a/pop-to-edx
12677     59/pop-to-ecx
12678     58/pop-to-eax
12679     # . epilogue
12680     89/<- %esp 5/r32/ebp
12681     5d/pop-to-ebp
12682     c3/return
12683 
12684 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)
12685     # . prologue
12686     55/push-ebp
12687     89/<- %ebp 4/r32/esp
12688     # . save registers
12689     51/push-ecx
12690     52/push-edx
12691     53/push-ebx
12692     56/push-esi
12693     57/push-edi
12694     # esi = table
12695     8b/-> *(ebp+8) 6/r32/esi
12696     # var curr/ecx: (addr row (handle array byte) (handle typeinfo-entry)) = table->data
12697     8d/copy-address *(esi+0xc) 1/r32/ecx
12698     # var max/edx: (addr byte) = &table->data[table->write]
12699     8b/-> *esi 2/r32/edx
12700     8d/copy-address *(ecx+edx) 2/r32/edx
12701     {
12702 $locate-typeinfo-entry-with-index:loop:
12703       39/compare %ecx 2/r32/edx
12704       73/jump-if-addr>= break/disp8
12705       # var v/eax: (addr typeinfo-entry)
12706       (lookup *(ecx+8) *(ecx+0xc))  # => eax
12707       # if (v->index == idx) return v
12708       8b/-> *(eax+8) 3/r32/ebx  # Typeinfo-entry-index
12709 #?       (write-buffered Stderr "comparing ")
12710 #?       (write-int32-hex-buffered Stderr %ebx)
12711 #?       (write-buffered Stderr " and ")
12712 #?       (write-int32-hex-buffered Stderr *(ebp+0xc))
12713 #?       (write-buffered Stderr Newline)
12714 #?       (flush Stderr)
12715       39/compare *(ebp+0xc) 3/r32/ebx
12716       74/jump-if-= $locate-typeinfo-entry-with-index:end/disp8
12717       # curr += Typeinfo-entry-size
12718       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-entry-size
12719       #
12720       eb/jump loop/disp8
12721     }
12722     # return 0
12723     b8/copy-to-eax 0/imm32
12724 $locate-typeinfo-entry-with-index:end:
12725 #?     (write-buffered Stderr "returning ")
12726 #?     (write-int32-hex-buffered Stderr %eax)
12727 #?     (write-buffered Stderr Newline)
12728 #?     (flush Stderr)
12729     # . restore registers
12730     5f/pop-to-edi
12731     5e/pop-to-esi
12732     5b/pop-to-ebx
12733     5a/pop-to-edx
12734     59/pop-to-ecx
12735     # . epilogue
12736     89/<- %esp 5/r32/ebp
12737     5d/pop-to-ebp
12738     c3/return
12739 
12740 dump-typeinfos:  # hdr: (addr array byte)
12741     # . prologue
12742     55/push-ebp
12743     89/<- %ebp 4/r32/esp
12744     # . save registers
12745     50/push-eax
12746     #
12747     (write-buffered Stderr *(ebp+8))
12748     (flush Stderr)
12749     # var curr/eax: (addr typeinfo) = lookup(Program->types)
12750     (lookup *_Program-types *_Program-types->payload)  # => eax
12751     {
12752       # if (curr == null) break
12753       3d/compare-eax-and 0/imm32
12754       74/jump-if-= break/disp8
12755       (write-buffered Stderr "---\n")
12756       (flush Stderr)
12757       (dump-typeinfo %eax)
12758       # curr = lookup(curr->next)
12759       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
12760       eb/jump loop/disp8
12761     }
12762 $dump-typeinfos:end:
12763     # . restore registers
12764     58/pop-to-eax
12765     # . epilogue
12766     89/<- %esp 5/r32/ebp
12767     5d/pop-to-ebp
12768     c3/return
12769 
12770 dump-typeinfo:  # in: (addr typeinfo)
12771     # . prologue
12772     55/push-ebp
12773     89/<- %ebp 4/r32/esp
12774     # . save registers
12775     50/push-eax
12776     51/push-ecx
12777     52/push-edx
12778     53/push-ebx
12779     56/push-esi
12780     57/push-edi
12781     # esi = in
12782     8b/-> *(ebp+8) 6/r32/esi
12783     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
12784     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
12785     89/<- %ecx 0/r32/eax
12786     (write-buffered Stderr "id:")
12787     (write-int32-hex-buffered Stderr *esi)
12788     (write-buffered Stderr "\n")
12789     (write-buffered Stderr "fields @ ")
12790     (write-int32-hex-buffered Stderr %ecx)
12791     (write-buffered Stderr Newline)
12792     (flush Stderr)
12793     (write-buffered Stderr "  write: ")
12794     (write-int32-hex-buffered Stderr *ecx)
12795     (write-buffered Stderr Newline)
12796     (flush Stderr)
12797     (write-buffered Stderr "  read: ")
12798     (write-int32-hex-buffered Stderr *(ecx+4))
12799     (write-buffered Stderr Newline)
12800     (flush Stderr)
12801     (write-buffered Stderr "  size: ")
12802     (write-int32-hex-buffered Stderr *(ecx+8))
12803     (write-buffered Stderr Newline)
12804     (flush Stderr)
12805     # var table-size/edx: int = table->write
12806     8b/-> *ecx 2/r32/edx  # stream-write
12807     # var curr/ecx: (addr table_row) = table->data
12808     8d/copy-address *(ecx+0xc) 1/r32/ecx
12809     # var max/edx: (addr table_row) = table->data + table->write
12810     8d/copy-address *(ecx+edx) 2/r32/edx
12811     {
12812 $dump-typeinfo:loop:
12813       # if (curr >= max) break
12814       39/compare %ecx 2/r32/edx
12815       0f 83/jump-if-addr>= break/disp32
12816       (write-buffered Stderr "  row:\n")
12817       (write-buffered Stderr "    key: ")
12818       (write-int32-hex-buffered Stderr *ecx)
12819       (write-buffered Stderr ",")
12820       (write-int32-hex-buffered Stderr *(ecx+4))
12821       (write-buffered Stderr " = '")
12822       (lookup *ecx *(ecx+4))
12823       (write-buffered Stderr %eax)
12824       (write-buffered Stderr "' @ ")
12825       (write-int32-hex-buffered Stderr %eax)
12826       (write-buffered Stderr Newline)
12827       (flush Stderr)
12828       (write-buffered Stderr "    value: ")
12829       (write-int32-hex-buffered Stderr *(ecx+8))
12830       (write-buffered Stderr ",")
12831       (write-int32-hex-buffered Stderr *(ecx+0xc))
12832       (write-buffered Stderr " = typeinfo-entry@")
12833       (lookup *(ecx+8) *(ecx+0xc))
12834       (write-int32-hex-buffered Stderr %eax)
12835       (write-buffered Stderr Newline)
12836       (flush Stderr)
12837       (write-buffered Stderr "        input var@")
12838       (dump-var 5 %eax)
12839       (lookup *(ecx+8) *(ecx+0xc))
12840       (write-buffered Stderr "        index: ")
12841       (write-int32-hex-buffered Stderr *(eax+8))
12842       (write-buffered Stderr Newline)
12843       (flush Stderr)
12844       (write-buffered Stderr "        output var@")
12845       8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
12846       (dump-var 5 %eax)
12847       (flush Stderr)
12848       # curr += row-size
12849       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
12850       #
12851       e9/jump loop/disp32
12852     }
12853 $dump-typeinfo:end:
12854     # . restore registers
12855     5f/pop-to-edi
12856     5e/pop-to-esi
12857     5b/pop-to-ebx
12858     5a/pop-to-edx
12859     59/pop-to-ecx
12860     58/pop-to-eax
12861     # . epilogue
12862     89/<- %esp 5/r32/ebp
12863     5d/pop-to-ebp
12864     c3/return
12865 
12866 dump-var:  # indent: int, v: (addr handle var)
12867     # . prologue
12868     55/push-ebp
12869     89/<- %ebp 4/r32/esp
12870     # . save registers
12871     50/push-eax
12872     53/push-ebx
12873     # eax = v
12874     8b/-> *(ebp+0xc) 0/r32/eax
12875     #
12876     (write-int32-hex-buffered Stderr *eax)
12877     (write-buffered Stderr ",")
12878     (write-int32-hex-buffered Stderr *(eax+4))
12879     (write-buffered Stderr "->")
12880     (lookup *eax *(eax+4))
12881     (write-int32-hex-buffered Stderr %eax)
12882     (write-buffered Stderr Newline)
12883     (flush Stderr)
12884     {
12885       3d/compare-eax-and 0/imm32
12886       0f 84/jump-if-= break/disp32
12887       (emit-indent Stderr *(ebp+8))
12888       (write-buffered Stderr "name: ")
12889       89/<- %ebx 0/r32/eax
12890       (write-int32-hex-buffered Stderr *ebx)  # Var-name
12891       (write-buffered Stderr ",")
12892       (write-int32-hex-buffered Stderr *(ebx+4))  # Var-name
12893       (write-buffered Stderr "->")
12894       (lookup *ebx *(ebx+4))  # Var-name
12895       (write-int32-hex-buffered Stderr %eax)
12896       {
12897         3d/compare-eax-and 0/imm32
12898         74/jump-if-= break/disp8
12899         (write-buffered Stderr Space)
12900         (write-buffered Stderr %eax)
12901       }
12902       (write-buffered Stderr Newline)
12903       (flush Stderr)
12904       (emit-indent Stderr *(ebp+8))
12905       (write-buffered Stderr "block depth: ")
12906       (write-int32-hex-buffered Stderr *(ebx+0x10))  # Var-block-depth
12907       (write-buffered Stderr Newline)
12908       (flush Stderr)
12909       (emit-indent Stderr *(ebp+8))
12910       (write-buffered Stderr "stack offset: ")
12911       (write-int32-hex-buffered Stderr *(ebx+0x14))  # Var-offset
12912       (write-buffered Stderr Newline)
12913       (flush Stderr)
12914       (emit-indent Stderr *(ebp+8))
12915       (write-buffered Stderr "reg: ")
12916       (write-int32-hex-buffered Stderr *(ebx+0x18))  # Var-register
12917       (write-buffered Stderr ",")
12918       (write-int32-hex-buffered Stderr *(ebx+0x1c))  # Var-register
12919       (write-buffered Stderr "->")
12920       (flush Stderr)
12921       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register
12922       (write-int32-hex-buffered Stderr %eax)
12923       {
12924         3d/compare-eax-and 0/imm32
12925         74/jump-if-= break/disp8
12926         (write-buffered Stderr Space)
12927         (write-buffered Stderr %eax)
12928       }
12929       (write-buffered Stderr Newline)
12930       (flush Stderr)
12931     }
12932 $dump-var:end:
12933     # . restore registers
12934     5b/pop-to-ebx
12935     58/pop-to-eax
12936     # . epilogue
12937     89/<- %esp 5/r32/ebp
12938     5d/pop-to-ebp
12939     c3/return
12940 
12941 #######################################################
12942 # Type-checking
12943 #######################################################
12944 
12945 check-mu-types:  # err: (addr buffered-file), ed: (addr exit-descriptor)
12946     # . prologue
12947     55/push-ebp
12948     89/<- %ebp 4/r32/esp
12949     # . save registers
12950     50/push-eax
12951     # var curr/eax: (addr function) = lookup(Program->functions)
12952     (lookup *_Program-functions *_Program-functions->payload)  # => eax
12953     {
12954 $check-mu-types:loop:
12955       # if (curr == null) break
12956       3d/compare-eax-and 0/imm32
12957       0f 84/jump-if-= break/disp32
12958 +--  8 lines: #?       # dump curr->name ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
12966       (check-mu-function %eax *(ebp+8) *(ebp+0xc))
12967       # curr = lookup(curr->next)
12968       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
12969       e9/jump loop/disp32
12970     }
12971 $check-mu-types:end:
12972     # . restore registers
12973     58/pop-to-eax
12974     # . epilogue
12975     89/<- %esp 5/r32/ebp
12976     5d/pop-to-ebp
12977     c3/return
12978 
12979 check-mu-function:  # fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12980     # . prologue
12981     55/push-ebp
12982     89/<- %ebp 4/r32/esp
12983     # . save registers
12984     50/push-eax
12985     # eax = f
12986     8b/-> *(ebp+8) 0/r32/eax
12987     # TODO: anything to check in header?
12988     # var body/eax: (addr block) = lookup(f->body)
12989     (lookup *(eax+0x18) *(eax+0x1c))  # Function-body Function-body => eax
12990     (check-mu-block %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10))
12991 $check-mu-function:end:
12992     # . restore registers
12993     58/pop-to-eax
12994     # . epilogue
12995     89/<- %esp 5/r32/ebp
12996     5d/pop-to-ebp
12997     c3/return
12998 
12999 check-mu-block:  # block: (addr block), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13000     # . prologue
13001     55/push-ebp
13002     89/<- %ebp 4/r32/esp
13003     # . save registers
13004     50/push-eax
13005     # eax = block
13006     8b/-> *(ebp+8) 0/r32/eax
13007     # var stmts/eax: (addr list stmt) = lookup(block->statements)
13008     (lookup *(eax+4) *(eax+8))  # Block-stmts Block-stmts => eax
13009     #
13010     {
13011 $check-mu-block:check-empty:
13012       3d/compare-eax-and 0/imm32
13013       0f 84/jump-if-= break/disp32
13014       # emit block->statements
13015       (check-mu-stmt-list %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13016     }
13017 $check-mu-block:end:
13018     # . restore registers
13019     58/pop-to-eax
13020     # . epilogue
13021     89/<- %esp 5/r32/ebp
13022     5d/pop-to-ebp
13023     c3/return
13024 
13025 check-mu-stmt-list:  # stmts: (addr list stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13026     # . prologue
13027     55/push-ebp
13028     89/<- %ebp 4/r32/esp
13029     # . save registers
13030     50/push-eax
13031     56/push-esi
13032     # esi = stmts
13033     8b/-> *(ebp+8) 6/r32/esi
13034     {
13035 $check-mu-stmt-list:loop:
13036       81 7/subop/compare %esi 0/imm32
13037       0f 84/jump-if-= break/disp32
13038       # var curr-stmt/eax: (addr stmt) = lookup(stmts->value)
13039       (lookup *esi *(esi+4))  # List-value List-value => eax
13040       {
13041 $check-mu-stmt-list:check-for-block:
13042         81 7/subop/compare *eax 0/imm32/block  # Stmt-tag
13043         75/jump-if-!= break/disp8
13044 $check-mu-stmt-list:block:
13045         (check-mu-block %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13046         eb/jump $check-mu-stmt-list:continue/disp8
13047       }
13048       {
13049 $check-mu-stmt-list:check-for-stmt1:
13050         81 7/subop/compare *eax 1/imm32/stmt1  # Stmt-tag
13051         0f 85/jump-if-!= break/disp32
13052 $check-mu-stmt-list:stmt1:
13053         (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13054         eb/jump $check-mu-stmt-list:continue/disp8
13055       }
13056       {
13057 $check-mu-stmt-list:check-for-reg-var-def:
13058         81 7/subop/compare *eax 3/imm32/reg-var-def  # Stmt-tag
13059         0f 85/jump-if-!= break/disp32
13060 $check-mu-stmt-list:reg-var-def:
13061         (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13062         eb/jump $check-mu-stmt-list:continue/disp8
13063       }
13064 $check-mu-stmt-list:continue:
13065       # TODO: raise an error on unrecognized Stmt-tag
13066       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
13067       89/<- %esi 0/r32/eax
13068       e9/jump loop/disp32
13069     }
13070 $check-mu-stmt-list:end:
13071     # . restore registers
13072     5e/pop-to-esi
13073     58/pop-to-eax
13074     # . epilogue
13075     89/<- %esp 5/r32/ebp
13076     5d/pop-to-ebp
13077     c3/return
13078 
13079 check-mu-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     50/push-eax
13085     # - if stmt's operation matches a primitive, check against it
13086     (has-primitive-name? *(ebp+8))  # => eax
13087     3d/compare-eax-and 0/imm32/false
13088     {
13089       74/jump-if-= break/disp8
13090       (check-mu-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13091       e9/jump $check-mu-stmt:end/disp32
13092     }
13093     # - otherwise find a function to check against
13094     # var f/eax: (addr function) = lookup(*Program->functions)
13095     (lookup *_Program-functions *_Program-functions->payload)  # => eax
13096     (find-matching-function %eax *(ebp+8))  # => eax
13097     3d/compare-eax-and 0/imm32
13098     {
13099       74/jump-if-= break/disp8
13100       (check-mu-call *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13101       eb/jump $check-mu-stmt:end/disp8
13102     }
13103     # var f/eax: (addr function) = lookup(*Program->signatures)
13104     (lookup *_Program-signatures *_Program-signatures->payload)  # => eax
13105     (find-matching-function %eax *(ebp+8))  # => eax
13106     3d/compare-eax-and 0/imm32
13107     {
13108       74/jump-if-= break/disp8
13109       (check-mu-call *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13110       eb/jump $check-mu-stmt:end/disp8
13111     }
13112     # - otherwise abort
13113     e9/jump $check-mu-stmt:unknown-call/disp32
13114 $check-mu-stmt:end:
13115     # . restore registers
13116     58/pop-to-eax
13117     # . epilogue
13118     89/<- %esp 5/r32/ebp
13119     5d/pop-to-ebp
13120     c3/return
13121 
13122 $check-mu-stmt:unknown-call:
13123     (write-buffered *(ebp+0x10) "unknown function '")
13124     8b/-> *(ebp+8) 0/r32/eax
13125     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
13126     (write-buffered *(ebp+0x10) %eax)
13127     (write-buffered *(ebp+0x10) "'\n")
13128     (flush *(ebp+0x10))
13129     (stop *(ebp+0x14) 1)
13130     # never gets here
13131 
13132 has-primitive-name?:  # stmt: (addr stmt) -> result/eax: boolean
13133     # . prologue
13134     55/push-ebp
13135     89/<- %ebp 4/r32/esp
13136     # . save registers
13137     51/push-ecx
13138     56/push-esi
13139     # var name/esi: (addr array byte) = lookup(stmt->operation)
13140     8b/-> *(ebp+8) 6/r32/esi
13141     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
13142     89/<- %esi 0/r32/eax
13143     # if (name == "get") return true
13144     (string-equal? %esi "get")  # => eax
13145     3d/compare-eax-and 0/imm32/false
13146     0f 85/jump-if-!= $has-primitive-name?:end/disp32
13147     # if (name == "index") return true
13148     (string-equal? %esi "index")  # => eax
13149     3d/compare-eax-and 0/imm32/false
13150     0f 85/jump-if-!= $has-primitive-name?:end/disp32
13151     # if (name == "length") return true
13152     (string-equal? %esi "length")  # => eax
13153     3d/compare-eax-and 0/imm32/false
13154     0f 85/jump-if-!= $has-primitive-name?:end/disp32
13155     # if (name == "compute-offset") return true
13156     (string-equal? %esi "compute-offset")  # => eax
13157     3d/compare-eax-and 0/imm32/false
13158     0f 85/jump-if-!= $has-primitive-name?:end/disp32
13159     # if (name == "copy-object") return true
13160     (string-equal? %esi "copy-object")  # => eax
13161     3d/compare-eax-and 0/imm32/false
13162     0f 85/jump-if-!= $has-primitive-name?:end/disp32
13163     # if (name == "allocate") return true
13164     (string-equal? %esi "allocate")  # => eax
13165     3d/compare-eax-and 0/imm32/false
13166     0f 85/jump-if-!= $has-primitive-name?:end/disp32
13167     # if (name == "populate") return true
13168     (string-equal? %esi "populate")  # => eax
13169     3d/compare-eax-and 0/imm32/false
13170     0f 85/jump-if-!= $has-primitive-name?:end/disp32
13171     # if (name == "populate-stream") return true
13172     (string-equal? %esi "populate-stream")  # => eax
13173     3d/compare-eax-and 0/imm32/false
13174     0f 85/jump-if-!= $has-primitive-name?:end/disp32
13175     # if (name == "read-from-stream") return true
13176     (string-equal? %esi "read-from-stream")  # => eax
13177     3d/compare-eax-and 0/imm32/false
13178     0f 85/jump-if-!= $has-primitive-name?:end/disp32
13179     # if (name == "write-to-stream") return true
13180     (string-equal? %esi "write-to-stream")  # => eax
13181     3d/compare-eax-and 0/imm32/false
13182     0f 85/jump-if-!= $has-primitive-name?:end/disp32
13183     # var curr/ecx: (addr primitive) = Primitives
13184     b9/copy-to-ecx Primitives/imm32
13185     {
13186 $has-primitive-name?:loop:
13187       # if (curr == null) break
13188       81 7/subop/compare %ecx 0/imm32
13189       74/jump-if-= break/disp8
13190       # if (primitive->name == name) return true
13191       (lookup *ecx *(ecx+4))  # Primitive-name Primitive-name => eax
13192 #?       (write-buffered Stderr %eax)
13193 #?       (write-buffered Stderr Newline)
13194 #?       (flush Stderr)
13195       (string-equal? %esi %eax)  # => eax
13196       3d/compare-eax-and 0/imm32/false
13197       75/jump-if-!= $has-primitive-name?:end/disp8
13198 $has-primitive-name?:next-primitive:
13199       # curr = curr->next
13200       (lookup *(ecx+0x3c) *(ecx+0x40))  # Primitive-next Primitive-next => eax
13201       89/<- %ecx 0/r32/eax
13202       #
13203       e9/jump loop/disp32
13204     }
13205     # return null
13206     b8/copy-to-eax 0/imm32
13207 $has-primitive-name?:end:
13208     # . restore registers
13209     5e/pop-to-esi
13210     59/pop-to-ecx
13211     # . epilogue
13212     89/<- %esp 5/r32/ebp
13213     5d/pop-to-ebp
13214     c3/return
13215 
13216 check-mu-primitive:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13217     # . prologue
13218     55/push-ebp
13219     89/<- %ebp 4/r32/esp
13220     # . save registers
13221     50/push-eax
13222     51/push-ecx
13223     # var op/ecx: (addr array byte) = lookup(stmt->operation)
13224     8b/-> *(ebp+8) 0/r32/eax
13225     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
13226     89/<- %ecx 0/r32/eax
13227     # if (op == "copy") check-mu-copy-stmt
13228     {
13229       (string-equal? %ecx "copy")  # => eax
13230       3d/compare-eax-and 0/imm32/false
13231       74/jump-if-= break/disp8
13232       (check-mu-copy-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13233       e9/jump $check-mu-primitive:end/disp32
13234     }
13235     # if (op == "copy-to") check-mu-copy-to-stmt
13236     {
13237       (string-equal? %ecx "copy-to")  # => eax
13238       3d/compare-eax-and 0/imm32/false
13239       74/jump-if-= break/disp8
13240       (check-mu-copy-to-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13241       e9/jump $check-mu-primitive:end/disp32
13242     }
13243     # if (op == "compare") check-mu-compare-stmt
13244     {
13245       (string-equal? %ecx "compare")  # => eax
13246       3d/compare-eax-and 0/imm32/false
13247       74/jump-if-= break/disp8
13248       (check-mu-compare-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13249       e9/jump $check-mu-primitive:end/disp32
13250     }
13251     # if (op == "address") check-mu-address-stmt
13252     {
13253       (string-equal? %ecx "address")  # => eax
13254       3d/compare-eax-and 0/imm32/false
13255       74/jump-if-= break/disp8
13256       (check-mu-address-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13257       e9/jump $check-mu-primitive:end/disp32
13258     }
13259     # if (op == "get") check-mu-get-stmt
13260     {
13261       (string-equal? %ecx "get")  # => eax
13262       3d/compare-eax-and 0/imm32/false
13263       74/jump-if-= break/disp8
13264       (check-mu-get-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13265       e9/jump $check-mu-primitive:end/disp32
13266     }
13267     # if (op == "index") check-mu-index-stmt
13268     {
13269       (string-equal? %ecx "index")  # => eax
13270       3d/compare-eax-and 0/imm32/false
13271       74/jump-if-= break/disp8
13272       (check-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13273       e9/jump $check-mu-primitive:end/disp32
13274     }
13275     # if (op == "length") check-mu-length-stmt
13276     {
13277       (string-equal? %ecx "length")  # => eax
13278       3d/compare-eax-and 0/imm32/false
13279       74/jump-if-= break/disp8
13280       (check-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13281       e9/jump $check-mu-primitive:end/disp32
13282     }
13283     # if (op == "compute-offset") check-mu-compute-offset-stmt
13284     {
13285       (string-equal? %ecx "compute-offset")  # => eax
13286       3d/compare-eax-and 0/imm32/false
13287       74/jump-if-= break/disp8
13288       (check-mu-compute-offset-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13289       e9/jump $check-mu-primitive:end/disp32
13290     }
13291     # if (op == "copy-object") check-mu-copy-object-stmt
13292     {
13293       (string-equal? %ecx "copy-object")  # => eax
13294       3d/compare-eax-and 0/imm32/false
13295       74/jump-if-= break/disp8
13296       (check-mu-copy-object-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13297       e9/jump $check-mu-primitive:end/disp32
13298     }
13299     # if (op == "allocate") check-mu-allocate-stmt
13300     {
13301       (string-equal? %ecx "allocate")  # => eax
13302       3d/compare-eax-and 0/imm32/false
13303       74/jump-if-= break/disp8
13304       (check-mu-allocate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13305       e9/jump $check-mu-primitive:end/disp32
13306     }
13307     # if (op == "populate") check-mu-populate-stmt
13308     {
13309       (string-equal? %ecx "populate")  # => eax
13310       3d/compare-eax-and 0/imm32/false
13311       74/jump-if-= break/disp8
13312       (check-mu-populate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13313       e9/jump $check-mu-primitive:end/disp32
13314     }
13315     # if (op == "populate-stream") check-mu-populate-stream-stmt
13316     {
13317       (string-equal? %ecx "populate-stream")  # => eax
13318       3d/compare-eax-and 0/imm32/false
13319       74/jump-if-= break/disp8
13320       (check-mu-populate-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13321       e9/jump $check-mu-primitive:end/disp32
13322     }
13323     # if (op == "read-from-stream") check-mu-read-from-stream-stmt
13324     {
13325       (string-equal? %ecx "read-from-stream")  # => eax
13326       3d/compare-eax-and 0/imm32/false
13327       74/jump-if-= break/disp8
13328       (check-mu-read-from-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13329       e9/jump $check-mu-primitive:end/disp32
13330     }
13331     # if (op == "write-to-stream") check-mu-write-to-stream-stmt
13332     {
13333       (string-equal? %ecx "write-to-stream")  # => eax
13334       3d/compare-eax-and 0/imm32/false
13335       74/jump-if-= break/disp8
13336       (check-mu-write-to-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13337       e9/jump $check-mu-primitive:end/disp32
13338     }
13339     # if (op == "convert") check-mu-convert-stmt
13340     {
13341       (string-equal? %ecx "convert")  # => eax
13342       3d/compare-eax-and 0/imm32/false
13343       74/jump-if-= break/disp8
13344       (check-mu-convert-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13345       e9/jump $check-mu-primitive:end/disp32
13346     }
13347     # otherwise check-numberlike-stmt
13348     (check-mu-numberlike-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13349 $check-mu-primitive:end:
13350     # . restore registers
13351     59/pop-to-ecx
13352     58/pop-to-eax
13353     # . epilogue
13354     89/<- %esp 5/r32/ebp
13355     5d/pop-to-ebp
13356     c3/return
13357 
13358 # by default, Mu primitives should only operate on 'number-like' types
13359 check-mu-numberlike-primitive:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13360     # . prologue
13361     55/push-ebp
13362     89/<- %ebp 4/r32/esp
13363     # . save registers
13364     50/push-eax
13365     51/push-ecx
13366     56/push-esi
13367     # esi = stmt
13368     8b/-> *(ebp+8) 6/r32/esi
13369     # var gas/ecx: int = 2
13370     b9/copy-to-ecx 2/imm32
13371     # - check at most 1 output
13372     # var output/eax: (addr stmt-var) = stmt->outputs
13373     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13374     {
13375       3d/compare-eax-and 0/imm32
13376       74/jump-if-= break/disp8
13377 $check-mu-numberlike-primitive:output:
13378       (check-mu-numberlike-output %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13379       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13380       3d/compare-eax-and 0/imm32
13381       0f 85/jump-if-!= $check-mu-numberlike-primitive:error-too-many-outputs/disp32
13382       # check output is in a register
13383       # --gas
13384       49/decrement-ecx
13385     }
13386     # - check first inout
13387     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13388     {
13389       3d/compare-eax-and 0/imm32
13390       0f 84/jump-if-= $check-mu-numberlike-primitive:end/disp32
13391 $check-mu-numberlike-primitive:first-inout:
13392       (check-mu-numberlike-arg %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13393       # --gas
13394       49/decrement-ecx
13395     }
13396     # - check second inout
13397     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13398     {
13399       3d/compare-eax-and 0/imm32
13400       74/jump-if-= $check-mu-numberlike-primitive:end/disp8
13401 $check-mu-numberlike-primitive:second-inout:
13402       # is a second inout allowed?
13403       81 7/subop/compare %ecx 0/imm32
13404       0f 84/jump-if-= $check-mu-numberlike-primitive:error-too-many-inouts/disp32
13405 $check-mu-numberlike-primitive:second-inout-permitted:
13406       (check-mu-numberlike-arg %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13407     }
13408 $check-mu-numberlike-primitive:third-inout:
13409     # if there's a third arg, raise an error
13410     81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
13411     0f 85/jump-if-!= $check-mu-numberlike-primitive:error-too-many-inouts/disp32
13412 $check-mu-numberlike-primitive:end:
13413     # . restore registers
13414     5e/pop-to-esi
13415     59/pop-to-ecx
13416     58/pop-to-eax
13417     # . epilogue
13418     89/<- %esp 5/r32/ebp
13419     5d/pop-to-ebp
13420     c3/return
13421 
13422 $check-mu-numberlike-primitive:error-too-many-inouts:
13423     (write-buffered *(ebp+0x10) "fn ")
13424     8b/-> *(ebp+0xc) 0/r32/eax
13425     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13426     (write-buffered *(ebp+0x10) %eax)
13427     (write-buffered *(ebp+0x10) ": stmt ")
13428     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
13429     (write-buffered *(ebp+0x10) %eax)
13430     (write-buffered *(ebp+0x10) ": too many inouts; most primitives support at most two arguments, across inouts and outputs\n")
13431     (flush *(ebp+0x10))
13432     (stop *(ebp+0x14) 1)
13433     # never gets here
13434 
13435 $check-mu-numberlike-primitive:error-too-many-outputs:
13436     (write-buffered *(ebp+0x10) "fn ")
13437     8b/-> *(ebp+0xc) 0/r32/eax
13438     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13439     (write-buffered *(ebp+0x10) %eax)
13440     (write-buffered *(ebp+0x10) ": stmt ")
13441     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
13442     (write-buffered *(ebp+0x10) %eax)
13443     (write-buffered *(ebp+0x10) ": too many outputs; most primitives support at most one output\n")
13444     (flush *(ebp+0x10))
13445     (stop *(ebp+0x14) 1)
13446     # never gets here
13447 
13448 check-mu-numberlike-arg:  # v: (addr stmt-var), stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13449     # . prologue
13450     55/push-ebp
13451     89/<- %ebp 4/r32/esp
13452     # . save registers
13453     50/push-eax
13454     56/push-esi
13455     # var t/esi: (addr type-tree) = lookup(v->value->type)
13456     8b/-> *(ebp+8) 0/r32/eax
13457     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13458     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
13459     89/<- %esi 0/r32/eax
13460 $check-mu-numberlike-arg:check-literal:
13461     # if t is an int, return
13462     (is-simple-mu-type? %esi 0)  # literal => eax
13463     3d/compare-eax-and 0/imm32/false
13464     75/jump-if-!= $check-mu-numberlike-arg:end/disp8
13465 $check-mu-numberlike-arg:check-addr:
13466     # if t is an addr and v is dereferenced, return
13467     {
13468       (is-mu-addr-type? %esi)  # => eax
13469       3d/compare-eax-and 0/imm32/false
13470       74/jump-if-= break/disp8
13471       8b/-> *(ebp+8) 0/r32/eax
13472       8b/-> *(eax+0x10) 0/r32/eax
13473       3d/compare-eax-and 0/imm32/false
13474       75/jump-if-!= $check-mu-numberlike-arg:end/disp8
13475     }
13476 $check-mu-numberlike-arg:output-checks:
13477     (check-mu-numberlike-output *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18))
13478 $check-mu-numberlike-arg:end:
13479     # . restore registers
13480     5e/pop-to-esi
13481     58/pop-to-eax
13482     # . epilogue
13483     89/<- %esp 5/r32/ebp
13484     5d/pop-to-ebp
13485     c3/return
13486 
13487 check-mu-numberlike-output:  # v: (addr stmt-var), stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13488     # . prologue
13489     55/push-ebp
13490     89/<- %ebp 4/r32/esp
13491     # . save registers
13492     50/push-eax
13493     56/push-esi
13494     # var t/esi: (addr type-tree) = lookup(v->value->type)
13495     8b/-> *(ebp+8) 0/r32/eax
13496     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13497     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
13498     89/<- %esi 0/r32/eax
13499 $check-mu-numberlike-output:check-int:
13500     # if t is an int, return
13501     (is-simple-mu-type? %esi 1)  # int => eax
13502     3d/compare-eax-and 0/imm32/false
13503     75/jump-if-!= $check-mu-numberlike-output:end/disp8
13504 $check-mu-numberlike-output:check-float:
13505     # if t is a float, return
13506     (is-simple-mu-type? %esi 0xf)  # float => eax
13507     3d/compare-eax-and 0/imm32/false
13508     75/jump-if-!= $check-mu-numberlike-output:end/disp8
13509 $check-mu-numberlike-output:check-boolean:
13510     # if t is a boolean, return
13511     (is-simple-mu-type? %esi 5)  # boolean => eax
13512     3d/compare-eax-and 0/imm32/false
13513     75/jump-if-!= $check-mu-numberlike-output:end/disp8
13514 $check-mu-numberlike-output:check-byte:
13515     # if t is a byte, return
13516     (is-simple-mu-type? %esi 8)  # byte => eax
13517     3d/compare-eax-and 0/imm32/false
13518     75/jump-if-!= $check-mu-numberlike-output:end/disp8
13519     e9/jump $check-mu-numberlike-output:fail/disp32
13520 $check-mu-numberlike-output:end:
13521     # . restore registers
13522     5e/pop-to-esi
13523     58/pop-to-eax
13524     # . epilogue
13525     89/<- %esp 5/r32/ebp
13526     5d/pop-to-ebp
13527     c3/return
13528 
13529 $check-mu-numberlike-output:fail:
13530     # otherwise raise an error
13531     (write-buffered *(ebp+0x14) "fn ")
13532     8b/-> *(ebp+0x10) 0/r32/eax
13533     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13534     (write-buffered *(ebp+0x14) %eax)
13535     (write-buffered *(ebp+0x14) ": stmt ")
13536     8b/-> *(ebp+0xc) 0/r32/eax
13537     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
13538     (write-buffered *(ebp+0x14) %eax)
13539     (write-buffered *(ebp+0x14) ": only non-addr scalar args permitted\n")
13540     (flush *(ebp+0x14))
13541     (stop *(ebp+0x18) 1)
13542     # never gets here
13543 
13544 check-mu-copy-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13545     # . prologue
13546     55/push-ebp
13547     89/<- %ebp 4/r32/esp
13548     # . save registers
13549 $check-mu-copy-stmt:end:
13550     # . restore registers
13551     # . epilogue
13552     89/<- %esp 5/r32/ebp
13553     5d/pop-to-ebp
13554     c3/return
13555 
13556 check-mu-copy-to-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13557     # . prologue
13558     55/push-ebp
13559     89/<- %ebp 4/r32/esp
13560     # . save registers
13561 $check-mu-copy-to-stmt:end:
13562     # . restore registers
13563     # . epilogue
13564     89/<- %esp 5/r32/ebp
13565     5d/pop-to-ebp
13566     c3/return
13567 
13568 check-mu-compare-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13569     # . prologue
13570     55/push-ebp
13571     89/<- %ebp 4/r32/esp
13572     # . save registers
13573 $check-mu-compare-stmt:end:
13574     # . restore registers
13575     # . epilogue
13576     89/<- %esp 5/r32/ebp
13577     5d/pop-to-ebp
13578     c3/return
13579 
13580 check-mu-address-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13581     # . prologue
13582     55/push-ebp
13583     89/<- %ebp 4/r32/esp
13584     # . save registers
13585 $check-mu-address-stmt:end:
13586     # . restore registers
13587     # . epilogue
13588     89/<- %esp 5/r32/ebp
13589     5d/pop-to-ebp
13590     c3/return
13591 
13592 check-mu-get-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13593     # . prologue
13594     55/push-ebp
13595     89/<- %ebp 4/r32/esp
13596     # . save registers
13597     50/push-eax
13598     51/push-ecx
13599     52/push-edx
13600     53/push-ebx
13601     56/push-esi
13602     57/push-edi
13603     # esi = stmt
13604     8b/-> *(ebp+8) 6/r32/esi
13605     # - check for 0 inouts
13606     # var base/ecx: (addr var) = stmt->inouts->value
13607     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13608     3d/compare-eax-and 0/imm32/false
13609     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-inouts/disp32
13610     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13611     89/<- %ecx 0/r32/eax
13612 $check-mu-get-stmt:check-base:
13613     # - check base type
13614     # if it's an 'addr', check that it's in a register
13615     # var base-type/ebx: (addr type-tree) = lookup(base->type)
13616     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
13617     89/<- %ebx 0/r32/eax
13618     {
13619       81 7/subop/compare *ebx 0/imm32/false  # Type-tree-is-atom
13620       0f 85/jump-if-!= break/disp32
13621 $check-mu-get-stmt:base-is-compound:
13622       # if (type->left != addr) break
13623       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
13624       (is-simple-mu-type? %eax 2)  # addr => eax
13625       3d/compare-eax-and 0/imm32/false
13626       74/jump-if-= break/disp8
13627 $check-mu-get-stmt:base-is-addr:
13628       # now check for register
13629       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
13630       0f 84/jump-if-= $check-mu-get-stmt:error-base-type-addr-but-not-register/disp32
13631 $check-mu-get-stmt:base-is-addr-in-register:
13632       # type->left is now an addr; skip it
13633       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
13634       81 7/subop/compare *(eax+0xc) 0/imm32  # Type-tree-right
13635       0f 85/jump-if-!= $check-mu-get-stmt:error-bad-base/disp32
13636 $check-mu-get-stmt:base-is-addr-to-atom-in-register:
13637       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
13638       89/<- %ebx 0/r32/eax
13639     }
13640 $check-mu-get-stmt:check-base-typeinfo:
13641     # ensure type is a container
13642     # var base-type-id/ebx: type-id = base-type->value
13643     8b/-> *(ebx+4) 3/r32/ebx  # Type-tree-value
13644     (is-container? %ebx)  # => eax
13645     3d/compare-eax-and 0/imm32/false
13646     0f 84/jump-if-= $check-mu-get-stmt:error-bad-base/disp32
13647     # var base-typeinfo/edx: (addr typeinfo) = find-typeinfo(base-type-id)
13648     # . var container/ecx: (handle typeinfo)
13649     68/push 0/imm32
13650     68/push 0/imm32
13651     89/<- %ecx 4/r32/esp
13652     # .
13653     (find-typeinfo %ebx %ecx)
13654     (lookup *ecx *(ecx+4))  # => eax
13655     # . reclaim container
13656     81 0/subop/add %esp 8/imm32
13657     # .
13658     89/<- %edx 0/r32/eax
13659     # var offset/ecx: (addr stmt-var) = stmt->inouts->next
13660     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13661     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13662     89/<- %ecx 0/r32/eax
13663     # - check for 1 inout
13664     3d/compare-eax-and 0/imm32/false
13665     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-inouts/disp32
13666     # var offset/ecx: (addr var) = lookup(offset->value)
13667     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
13668     89/<- %ecx 0/r32/eax
13669     # - check for valid field
13670     81 7/subop/compare *(ecx+0x14) -1/imm32/uninitialized  # Var-offset
13671     0f 84/jump-if-= $check-mu-get-stmt:error-bad-field/disp32
13672     # - check for too many inouts
13673     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13674     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13675     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13676     3d/compare-eax-and 0/imm32/false
13677     0f 85/jump-if-!= $check-mu-get-stmt:error-too-many-inouts/disp32
13678     # var output/edi: (addr var) = stmt->outputs->value
13679     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13680     # - check for 0 outputs
13681     3d/compare-eax-and 0/imm32/false
13682     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-outputs/disp32
13683     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13684     89/<- %edi 0/r32/eax
13685 $check-mu-get-stmt:check-output-type:
13686     # - check output type
13687     # must be in register
13688     (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
13689     3d/compare-eax-and 0/imm32
13690     0f 84/jump-if-= $check-mu-get-stmt:error-output-not-in-register/disp32
13691     # must have a non-atomic type
13692     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
13693     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
13694     0f 85/jump-if-!= $check-mu-get-stmt:error-output-type-not-address/disp32
13695     # type must start with (addr ...)
13696     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
13697     (is-simple-mu-type? %eax 2)  # => eax
13698     3d/compare-eax-and 0/imm32/false
13699     0f 84/jump-if-= $check-mu-get-stmt:error-output-type-not-address/disp32
13700 $check-mu-get-stmt:check-output-type-match:
13701     # payload of addr type must match 'type' definition
13702     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
13703     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
13704     # if (payload->right == null) payload = payload->left
13705     81 7/subop/compare *(eax+0xc) 0/imm32/null  # Type-tree-right
13706     {
13707       75/jump-if-!= break/disp8
13708       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
13709     }
13710     89/<- %edi 0/r32/eax
13711     # . var output-name/ecx: (addr array byte)
13712     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13713     89/<- %ecx 0/r32/eax
13714     # . var base-typeinfo-entry/eax: (addr handle typeinfo-entry)
13715     (lookup *(edx+4) *(edx+8))  # Typeinfo-fields Typeinfo-fields => eax
13716     (get %eax %ecx 0x10)  # => eax
13717     # .
13718     (lookup *eax *(eax+4))  # => eax
13719     (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
13720     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
13721     # .
13722     (type-equal? %edi %eax)  # => eax
13723     3d/compare-eax-and 0/imm32/false
13724     0f 84/jump-if-= $check-mu-get-stmt:error-bad-output-type/disp32
13725     # - check for too many outputs
13726     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13727     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13728     3d/compare-eax-and 0/imm32/false
13729     0f 85/jump-if-!= $check-mu-get-stmt:error-too-many-outputs/disp32
13730 $check-mu-get-stmt:end:
13731     # . restore registers
13732     5f/pop-to-edi
13733     5e/pop-to-esi
13734     5b/pop-to-ebx
13735     5a/pop-to-edx
13736     59/pop-to-ecx
13737     58/pop-to-eax
13738     # . epilogue
13739     89/<- %esp 5/r32/ebp
13740     5d/pop-to-ebp
13741     c3/return
13742 
13743 $check-mu-get-stmt:error-too-few-inouts:
13744     (write-buffered *(ebp+0x10) "fn ")
13745     8b/-> *(ebp+0xc) 0/r32/eax
13746     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13747     (write-buffered *(ebp+0x10) %eax)
13748     (write-buffered *(ebp+0x10) ": stmt get: too few inouts (2 required)\n")
13749     (flush *(ebp+0x10))
13750     (stop *(ebp+0x14) 1)
13751     # never gets here
13752 
13753 $check-mu-get-stmt:error-too-many-inouts:
13754     (write-buffered *(ebp+0x10) "fn ")
13755     8b/-> *(ebp+0xc) 0/r32/eax
13756     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13757     (write-buffered *(ebp+0x10) %eax)
13758     (write-buffered *(ebp+0x10) ": stmt get: too many inouts (2 required)\n")
13759     (flush *(ebp+0x10))
13760     (stop *(ebp+0x14) 1)
13761     # never gets here
13762 
13763 $check-mu-get-stmt:error-too-few-outputs:
13764     (write-buffered *(ebp+0x10) "fn ")
13765     8b/-> *(ebp+0xc) 0/r32/eax
13766     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13767     (write-buffered *(ebp+0x10) %eax)
13768     (write-buffered *(ebp+0x10) ": stmt get: must have an output\n")
13769     (flush *(ebp+0x10))
13770     (stop *(ebp+0x14) 1)
13771     # never gets here
13772 
13773 $check-mu-get-stmt:error-too-many-outputs:
13774     (write-buffered *(ebp+0x10) "fn ")
13775     8b/-> *(ebp+0xc) 0/r32/eax
13776     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13777     (write-buffered *(ebp+0x10) %eax)
13778     (write-buffered *(ebp+0x10) ": stmt get: too many outputs (1 required)\n")
13779     (flush *(ebp+0x10))
13780     (stop *(ebp+0x14) 1)
13781     # never gets here
13782 
13783 $check-mu-get-stmt:error-bad-base:
13784     # error("fn " fn ": stmt get: var '" base->name "' must have a 'type' definition\n")
13785     (write-buffered *(ebp+0x10) "fn ")
13786     8b/-> *(ebp+0xc) 0/r32/eax
13787     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13788     (write-buffered *(ebp+0x10) %eax)
13789     (write-buffered *(ebp+0x10) ": stmt get: var '")
13790     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13791     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13792     (lookup *eax *(eax+4))  # Var-name Var-name => eax
13793     (write-buffered *(ebp+0x10) %eax)
13794     (write-buffered *(ebp+0x10) "' must have a 'type' definition\n")
13795     (flush *(ebp+0x10))
13796     (stop *(ebp+0x14) 1)
13797     # never gets here
13798 
13799 $check-mu-get-stmt:error-base-type-addr-but-not-register:
13800     (write-buffered *(ebp+0x10) "fn ")
13801     8b/-> *(ebp+0xc) 0/r32/eax
13802     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13803     (write-buffered *(ebp+0x10) %eax)
13804     (write-buffered *(ebp+0x10) ": stmt get: var '")
13805     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13806     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13807     (lookup *eax *(eax+4))  # Var-name Var-name => eax
13808     (write-buffered *(ebp+0x10) %eax)
13809     (write-buffered *(ebp+0x10) "' is an 'addr' type, and so must live in a register\n")
13810     (flush *(ebp+0x10))
13811     (stop *(ebp+0x14) 1)
13812     # never gets here
13813 
13814 $check-mu-get-stmt:error-bad-field:
13815     # error("fn " fn ": stmt get: type " type " has no member called '" curr->name "'\n")
13816     (write-buffered *(ebp+0x10) "fn ")
13817     8b/-> *(ebp+0xc) 0/r32/eax
13818     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13819     (write-buffered *(ebp+0x10) %eax)
13820     (write-buffered *(ebp+0x10) ": stmt get: type '")
13821     # . write(Type-id->data[tmp])
13822     bf/copy-to-edi Type-id/imm32
13823     (write-buffered *(ebp+0x10) *(edi+ebx<<2+0xc))
13824     # .
13825     (write-buffered *(ebp+0x10) "' has no member called '")
13826     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13827     (write-buffered *(ebp+0x10) %eax)
13828     (write-buffered *(ebp+0x10) "'\n")
13829     (flush *(ebp+0x10))
13830     (stop *(ebp+0x14) 1)
13831     # never gets here
13832 
13833 $check-mu-get-stmt:error-output-not-in-register:
13834     (write-buffered *(ebp+0x10) "fn ")
13835     8b/-> *(ebp+0xc) 0/r32/eax
13836     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13837     (write-buffered *(ebp+0x10) %eax)
13838     (write-buffered *(ebp+0x10) ": stmt get: output '")
13839     (lookup *edi *(edi+4))  # Var-name Var-name => eax
13840     (write-buffered *(ebp+0x10) %eax)
13841     (write-buffered *(ebp+0x10) "' is not in a register\n")
13842     (flush *(ebp+0x10))
13843     (stop *(ebp+0x14) 1)
13844     # never gets here
13845 
13846 $check-mu-get-stmt:error-output-type-not-address:
13847     (write-buffered *(ebp+0x10) "fn ")
13848     8b/-> *(ebp+0xc) 0/r32/eax
13849     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13850     (write-buffered *(ebp+0x10) %eax)
13851     (write-buffered *(ebp+0x10) ": stmt get: output must be an address\n")
13852     (flush *(ebp+0x10))
13853     (stop *(ebp+0x14) 1)
13854     # never gets here
13855 
13856 $check-mu-get-stmt:error-bad-output-type:
13857     (write-buffered *(ebp+0x10) "fn ")
13858     8b/-> *(ebp+0xc) 0/r32/eax
13859     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13860     (write-buffered *(ebp+0x10) %eax)
13861     (write-buffered *(ebp+0x10) ": stmt get: wrong output type for member '")
13862     (write-buffered *(ebp+0x10) %ecx)
13863     (write-buffered *(ebp+0x10) "' of type '")
13864     bf/copy-to-edi Type-id/imm32
13865     (write-buffered *(ebp+0x10) *(edi+ebx<<2+0xc))
13866     (write-buffered *(ebp+0x10) "'\n")
13867     (flush *(ebp+0x10))
13868     (stop *(ebp+0x14) 1)
13869     # never gets here
13870 
13871 check-mu-index-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13872     # . prologue
13873     55/push-ebp
13874     89/<- %ebp 4/r32/esp
13875     # . save registers
13876     50/push-eax
13877     51/push-ecx
13878     52/push-edx
13879     53/push-ebx
13880     56/push-esi
13881     57/push-edi
13882     # esi = stmt
13883     8b/-> *(ebp+8) 6/r32/esi
13884     # - check for 0 inouts
13885     # var base/ecx: (addr var) = stmt->inouts->value
13886     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13887 $check-mu-index-stmt:check-no-inouts:
13888     3d/compare-eax-and 0/imm32
13889     0f 84/jump-if-= $check-mu-index-stmt:error-too-few-inouts/disp32
13890     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13891     89/<- %ecx 0/r32/eax
13892     # - check base type is either (addr array ...) in register or (array ...) on stack
13893     # var base-type/ebx: (addr type-tree) = lookup(base->type)
13894     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
13895     89/<- %ebx 0/r32/eax
13896     # if base-type is an atom, abort with a precise error
13897     81 7/subop/compare *ebx 0/imm32/false  # Type-tree-is-atom
13898     {
13899       74/jump-if-= break/disp8
13900       (is-simple-mu-type? %ebx 3)  # array => eax
13901       3d/compare-eax-and 0/imm32/false
13902       0f 85/jump-if-!= $check-mu-index-stmt:error-base-array-atom-type/disp32
13903       0f 84/jump-if-= $check-mu-index-stmt:error-base-non-array-type/disp32
13904     }
13905 $check-mu-index-stmt:base-is-compound:
13906     # if type->left not addr or array, abort
13907     {
13908       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
13909       (is-simple-mu-type? %eax 2)  # addr => eax
13910       3d/compare-eax-and 0/imm32/false
13911       75/jump-if-!= break/disp8
13912       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
13913       (is-simple-mu-type? %eax 3)  # array => eax
13914       3d/compare-eax-and 0/imm32/false
13915       75/jump-if-!= break/disp8
13916       e9/jump $check-mu-index-stmt:error-base-non-array-type/disp32
13917     }
13918     # if (type->left == addr) ensure type->right->left == array and type->register exists
13919     {
13920       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
13921       (is-simple-mu-type? %eax 2)  # addr => eax
13922       3d/compare-eax-and 0/imm32/false
13923       74/jump-if-= break/disp8
13924 $check-mu-index-stmt:base-is-addr:
13925       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
13926       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
13927       (is-simple-mu-type? %eax 3)  # array => eax
13928       3d/compare-eax-and 0/imm32/false
13929       0f 84/jump-if-= $check-mu-index-stmt:error-base-non-array-type/disp32
13930 $check-mu-index-stmt:check-base-addr-is-register:
13931       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
13932       0f 84/jump-if-= $check-mu-index-stmt:error-base-address-array-type-on-stack/disp32
13933     }
13934     # if (type->left == array) ensure type->register doesn't exist
13935     {
13936       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
13937       (is-simple-mu-type? %eax 3)  # array => eax
13938       3d/compare-eax-and 0/imm32/false
13939       74/jump-if-= break/disp8
13940 $check-mu-index-stmt:base-is-array:
13941       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
13942       0f 85/jump-if-!= $check-mu-index-stmt:error-base-array-type-in-register/disp32
13943     }
13944     # if (base-type->left == addr) base-type = base-type->right
13945     {
13946       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
13947       (is-simple-mu-type? %eax 2)  # addr => eax
13948       3d/compare-eax-and 0/imm32/false
13949       74/jump-if-= break/disp8
13950       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
13951       89/<- %ebx 0/r32/eax
13952     }
13953     # - check for 1 inout
13954     # var index/ecx: (addr stmt-var) = stmt->inouts->next->value
13955     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13956     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13957 $check-mu-index-stmt:check-single-inout:
13958     3d/compare-eax-and 0/imm32
13959     0f 84/jump-if-= $check-mu-index-stmt:error-too-few-inouts/disp32
13960     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13961     89/<- %ecx 0/r32/eax
13962     # - check index is either a literal or register
13963     # var index-type/edx: (addr type-tree)
13964     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
13965     89/<- %edx 0/r32/eax
13966     # if index type is an atom, it must be a literal or int
13967     81 7/subop/compare *edx 0/imm32/false  # Type-tree-is-atom
13968     {
13969       74/jump-if-= break/disp8
13970 $check-mu-index-stmt:index-type-is-atom:
13971       (is-simple-mu-type? %edx 0)  # literal => eax
13972       3d/compare-eax-and 0/imm32/false
13973       75/jump-if-!= $check-mu-index-stmt:index-type-done/disp8
13974       (is-simple-mu-type? %edx 1)  # int => eax
13975       3d/compare-eax-and 0/imm32/false
13976       75/jump-if-!= $check-mu-index-stmt:index-type-done/disp8
13977       (is-simple-mu-type? %edx 7)  # offset => eax
13978       3d/compare-eax-and 0/imm32/false
13979       0f 85/jump-if-!= $check-mu-index-stmt:error-index-offset-atom-type/disp32
13980       e9/jump $check-mu-index-stmt:error-invalid-index-type/disp32
13981     }
13982     # if index type is a non-atom: it must be an offset
13983     {
13984       75/jump-if-!= break/disp8
13985 $check-mu-index-stmt:index-type-is-non-atom:
13986       (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
13987       (is-simple-mu-type? %eax 7)  # offset => eax
13988       3d/compare-eax-and 0/imm32/false
13989       0f 84/jump-if-= $check-mu-index-stmt:error-invalid-index-type/disp32
13990     }
13991 $check-mu-index-stmt:index-type-done:
13992     # check index is either a literal or in a register
13993     {
13994       (is-simple-mu-type? %edx 0)  # literal => eax
13995       3d/compare-eax-and 0/imm32/false
13996       75/jump-if-!= break/disp8
13997 $check-mu-index-stmt:check-index-in-register:
13998       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
13999       0f 84/jump-if-= $check-mu-index-stmt:error-index-on-stack/disp32
14000     }
14001     # - if index is an 'int', check that element type of base has size 1, 2, 4 or 8 bytes.
14002     {
14003       (is-simple-mu-type? %edx 1)  # int => eax
14004       3d/compare-eax-and 0/imm32/false
14005       74/jump-if-= break/disp8
14006 $check-mu-index-stmt:check-index-can-be-int:
14007       (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
14008       (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
14009       (array-element-size %eax)  # => eax
14010       3d/compare-eax-and 1/imm32
14011       74/jump-if-= break/disp8
14012       3d/compare-eax-and 2/imm32
14013       74/jump-if-= break/disp8
14014       3d/compare-eax-and 4/imm32
14015       74/jump-if-= break/disp8
14016       3d/compare-eax-and 8/imm32
14017       74/jump-if-= break/disp8
14018       e9/jump $check-mu-index-stmt:error-index-needs-offset/disp32
14019     }
14020     # - check for too many inouts
14021     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
14022     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
14023     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
14024     3d/compare-eax-and 0/imm32/false
14025     0f 85/jump-if-!= $check-mu-index-stmt:error-too-many-inouts/disp32
14026     # - check for 0 outputs
14027     # var output/edi: (addr var) = stmt->outputs->value
14028     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
14029     3d/compare-eax-and 0/imm32/false
14030     0f 84/jump-if-= $check-mu-index-stmt:error-too-few-outputs/disp32
14031     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
14032     89/<- %edi 0/r32/eax
14033     # - check output type
14034     # must have a non-atomic type
14035     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
14036     89/<- %edx 0/r32/eax
14037     81 7/subop/compare *edx 0/imm32/false  # Type-tree-is-atom
14038     0f 85/jump-if-!= $check-mu-index-stmt:error-output-type-not-address/disp32
14039     # type must start with (addr ...)
14040     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
14041     (is-simple-mu-type? %eax 2)  # addr => eax
14042     3d/compare-eax-and 0/imm32/false
14043     0f 84/jump-if-= $check-mu-index-stmt:error-output-type-not-address/disp32
14044     # if tail(base-type) != tail(output-type) abort
14045     (type-tail %ebx)  # => eax
14046     89/<- %ebx 0/r32/eax
14047     (type-tail %edx)  # => eax
14048     (type-equal? %ebx %eax)  # => eax
14049     3d/compare-eax-and 0/imm32/false
14050     0f 84/jump-if-= $check-mu-index-stmt:error-bad-output-type/disp32
14051     # - check for too many outputs
14052     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
14053     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
14054     3d/compare-eax-and 0/imm32/false
14055     0f 85/jump-if-!= $check-mu-index-stmt:error-too-many-outputs/disp32
14056 $check-mu-index-stmt:end:
14057     # . restore registers
14058     5f/pop-to-edi
14059     5e/pop-to-esi
14060     5b/pop-to-ebx
14061     5a/pop-to-edx
14062     59/pop-to-ecx
14063     58/pop-to-eax
14064     # . epilogue
14065     89/<- %esp 5/r32/ebp
14066     5d/pop-to-ebp
14067     c3/return
14068 
14069 $check-mu-index-stmt:error-base-non-array-type:
14070     (write-buffered *(ebp+0x10) "fn ")
14071     8b/-> *(ebp+0xc) 0/r32/eax
14072     (lookup *eax *(eax+4))  # Function-name Function-name => eax
14073     (write-buffered *(ebp+0x10) %eax)
14074     (write-buffered *(ebp+0x10) ": stmt index: var '")
14075     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
14076     (write-buffered *(ebp+0x10) %eax)
14077     (write-buffered *(ebp+0x10) "' is not an array\n")
14078     (flush *(ebp+0x10))
14079     (stop *(ebp+0x14) 1)
14080     # never gets here
14081 
14082 $check-mu-index-stmt:error-base-array-atom-type:
14083     (write-buffered *(ebp+0x10) "fn ")
14084     8b/-> *(ebp+0xc) 0/r32/eax
14085     (lookup *eax *(eax+4))  # Function-name Function-name => eax
14086     (write-buffered *(ebp+0x10) %eax)
14087     (write-buffered *(ebp+0x10) ": stmt index: array '")
14088     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
14089     (write-buffered *(ebp+0x10) %eax)
14090     (write-buffered *(ebp+0x10) "' must specify the type of its elements\n")
14091     (flush *(ebp+0x10))
14092     (stop *(ebp+0x14) 1)
14093     # never gets here
14094 
14095 $check-mu-index-stmt:error-base-address-array-type-on-stack:
14096     (write-buffered *(ebp+0x10) "fn ")
14097     8b/-> *(ebp+0xc) 0/r32/eax
14098     (lookup *eax *(eax+4))  # Function-name Function-name => eax
14099     (write-buffered *(ebp+0x10) %eax)
14100     (write-buffered *(ebp+0x10) ": stmt index: var '")
14101     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
14102     (write-buffered *(ebp+0x10) %eax)
14103     (write-buffered *(ebp+0x10) "' is an addr to an array, and so must live in a register\n")
14104     (flush *(ebp+0x10))
14105     (stop *(ebp+0x14) 1)
14106     # never gets here
14107 
14108 $check-mu-index-stmt:error-base-array-type-in-register:
14109     (write-buffered *(ebp+0x10) "fn ")
14110     8b/-> *(ebp+0xc) 0/r32/eax
14111     (lookup *eax *(eax+4))  # Function-name Function-name => eax
14112     (write-buffered *(ebp+0x10) %eax)
14113     (write-buffered *(ebp+0x10) ": stmt index: var '")
14114     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
14115     (write-buffered *(ebp+0x10) %eax)
14116     (write-buffered *(ebp+0x10) "' is an array, and so must live on the stack\n")
14117     (flush *(ebp+0x10))
14118     (stop *(ebp+0x14) 1)
14119     # never gets here
14120 
14121 $check-mu-index-stmt:error-too-few-inouts:
14122     (write-buffered *(ebp+0x10) "fn ")
14123     8b/-> *(ebp+0xc) 0/r32/eax
14124     (lookup *eax *(eax+4))  # Function-name Function-name => eax
14125     (write-buffered *(ebp+0x10) %eax)
14126     (write-buffered *(ebp+0x10) ": stmt index: too few inouts (2 required)\n")
14127     (flush *(ebp+0x10))
14128     (stop *(ebp+0x14) 1)
14129     # never gets here
14130 
14131 $check-mu-index-stmt:error-invalid-index-type:
14132     (write-buffered *(ebp+0x10) "fn ")
14133     8b/-> *(ebp+0xc) 0/r32/eax
14134     (lookup *eax *(eax+4))  # Function-name Function-name => eax
14135     (write-buffered *(ebp+0x10) %eax)
14136     (write-buffered *(ebp+0x10) ": stmt index: second argument '")
14137     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
14138     (write-buffered *(ebp+0x10) %eax)
14139     (write-buffered *(ebp+0x10) "' must be an int or offset\n")
14140     (flush *(ebp+0x10))
14141     (stop *(ebp+0x14) 1)
14142     # never gets here
14143 
14144 $check-mu-index-stmt:error-index-offset-atom-type:
14145     (write-buffered *(ebp+0x10) "fn ")
14146     8b/-> *(ebp+0xc) 0/r32/eax
14147     (lookup *eax *(eax+4))  # Function-name Function-name => eax
14148     (write-buffered *(ebp+0x10) %eax)
14149     (write-buffered *(ebp+0x10) ": stmt index: offset '")
14150     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
14151     (write-buffered *(ebp+0x10) %eax)
14152     (write-buffered *(ebp+0x10) "' must specify the type of array elements\n")
14153     (flush *(ebp+0x10))
14154     (stop *(ebp+0x14) 1)
14155     # never gets here
14156 
14157 $check-mu-index-stmt:error-index-on-stack:
14158     (write-buffered *(ebp+0x10) "fn ")
14159     8b/-> *(ebp+0xc) 0/r32/eax
14160     (lookup *eax *(eax+4))  # Function-name Function-name => eax
14161     (write-buffered *(ebp+0x10) %eax)
14162     (write-buffered *(ebp+0x10) ": stmt index: second argument '")
14163     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
14164     (write-buffered *(ebp+0x10) %eax)
14165     (write-buffered *(ebp+0x10) "' must be in a register\n")
14166     (flush *(ebp+0x10))
14167     (stop *(ebp+0x14) 1)
14168     # never gets here
14169 
14170 $check-mu-index-stmt:error-index-needs-offset:
14171     (write-buffered *(ebp+0x10) "fn ")
14172     8b/-> *(ebp+0xc) 0/r32/eax
14173     (lookup *eax *(eax+4))  # Function-name Function-name => eax
14174     (write-buffered *(ebp+0x10) %eax)
14175     (write-buffered *(ebp+0x10) ": stmt index: cannot take an int for array '")
14176     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
14177     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
14178     (lookup *eax *(eax+4))  # Var-name Var-name => eax
14179     (write-buffered *(ebp+0x10) %eax)
14180     (write-buffered *(ebp+0x10) "'; create an offset instead. See mu.md for details.\n")
14181     (flush *(ebp+0x10))
14182     (stop *(ebp+0x14) 1)
14183     # never gets here
14184 
14185 $check-mu-index-stmt:error-too-many-inouts:
14186     (write-buffered *(ebp+0x10) "fn ")
14187     8b/-> *(ebp+0xc) 0/r32/eax
14188     (lookup *eax *(eax+4))  # Function-name Function-name => eax
14189     (write-buffered *(ebp+0x10) %eax)
14190     (write-buffered *(ebp+0x10) ": stmt index: too many inouts (2 required)\n")
14191     (flush *(ebp+0x10))
14192     (stop *(ebp+0x14) 1)
14193     # never gets here
14194 
14195 $check-mu-index-stmt:error-too-few-outputs:
14196     (write-buffered *(ebp+0x10) "fn ")
14197     8b/-> *(ebp+0xc) 0/r32/eax
14198     (lookup *eax *(eax+4))  # Function-name Function-name => eax
14199     (write-buffered *(ebp+0x10) %eax)
14200     (write-buffered *(ebp+0x10) ": stmt index: must have an output\n")
14201     (flush *(ebp+0x10))
14202     (stop *(ebp+0x14) 1)
14203     # never gets here
14204 
14205 $check-mu-index-stmt:error-too-many-outputs:
14206     (write-buffered *(ebp+0x10) "fn ")
14207     8b/-> *(ebp+0xc) 0/r32/eax
14208     (lookup *eax *(eax+4))  # Function-name Function-name => eax
14209     (write-buffered *(ebp+0x10) %eax)
14210     (write-buffered *(ebp+0x10) ": stmt index: too many outputs (1 required)\n")
14211     (flush *(ebp+0x10))
14212     (stop *(ebp+0x14) 1)
14213     # never gets here
14214 
14215 $check-mu-index-stmt:error-output-not-in-register:
14216     (write-buffered *(ebp+0x10) "fn ")
14217     8b/-> *(ebp+0xc) 0/r32/eax
14218     (lookup *eax *(eax+4))  # Function-name Function-name => eax
14219     (write-buffered *(ebp+0x10) %eax)
14220     (write-buffered *(ebp+0x10) ": stmt index: output '")
14221     (lookup *edi *(edi+4))  # Var-name Var-name => eax
14222     (write-buffered *(ebp+0x10) %eax)
14223     (write-buffered *(ebp+0x10) "' is not in a register\n")
14224     (flush *(ebp+0x10))
14225     (stop *(ebp+0x14) 1)
14226     # never gets here
14227 
14228 $check-mu-index-stmt:error-output-type-not-address:
14229     (write-buffered *(ebp+0x10) "fn ")
14230     8b/-> *(ebp+0xc) 0/r32/eax
14231     (lookup *eax *(eax+4))  # Function-name Function-name => eax
14232     (write-buffered *(ebp+0x10) %eax)
14233     (write-buffered *(ebp+0x10) ": stmt index: output '")
14234     (lookup *edi *(edi+4))  # Var-name Var-name => eax
14235     (write-buffered *(ebp+0x10) %eax)
14236     (write-buffered *(ebp+0x10) "' must be an address\n")
14237     (flush *(ebp+0x10))
14238     (stop *(ebp+0x14) 1)
14239     # never gets here
14240 
14241 $check-mu-index-stmt:error-bad-output-type:
14242     (write-buffered *(ebp+0x10) "fn ")
14243     8b/-> *(ebp+0xc) 0/r32/eax
14244     (lookup *eax *(eax+4))  # Function-name Function-name => eax
14245     (write-buffered *(ebp+0x10) %eax)
14246     (write-buffered *(ebp+0x10) ": stmt index: output '")
14247     (lookup *edi *(edi+4))  # Var-name Var-name => eax
14248     (write-buffered *(ebp+0x10) %eax)
14249     (write-buffered *(ebp+0x10) "' does not have the right type\n")
14250     (flush *(ebp+0x10))
14251     (stop *(ebp+0x14) 1)
14252     # never gets here
14253 
14254 check-mu-length-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
14255     # . prologue
14256     55/push-ebp
14257     89/<- %ebp 4/r32/esp
14258     # . save registers
14259 $check-mu-length-stmt:end:
14260     # . restore registers
14261     # . epilogue
14262     89/<- %esp 5/r32/ebp
14263     5d/pop-to-ebp
14264     c3/return
14265 
14266 check-mu-compute-offset-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
14267     # . prologue
14268     55/push-ebp
14269     89/<- %ebp 4/r32/esp
14270     # . save registers
14271 $check-mu-compute-offset-stmt:end:
14272     # . restore registers
14273     # . epilogue
14274     89/<- %esp 5/r32/ebp
14275     5d/pop-to-ebp
14276     c3/return
14277 
14278 check-mu-copy-object-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
14279     # . prologue
14280     55/push-ebp
14281     89/<- %ebp 4/r32/esp
14282     # . save registers
14283 $check-mu-copy-object-stmt:end:
14284     # . restore registers
14285     # . epilogue
14286     89/<- %esp 5/r32/ebp
14287     5d/pop-to-ebp
14288     c3/return
14289 
14290 check-mu-allocate-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
14291     # . prologue
14292     55/push-ebp
14293     89/<- %ebp 4/r32/esp
14294     # . save registers
14295 $check-mu-allocate-stmt:end:
14296     # . restore registers
14297     # . epilogue
14298     89/<- %esp 5/r32/ebp
14299     5d/pop-to-ebp
14300     c3/return
14301 
14302 check-mu-populate-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
14303     # . prologue
14304     55/push-ebp
14305     89/<- %ebp 4/r32/esp
14306     # . save registers
14307 $check-mu-populate-stmt:end:
14308     # . restore registers
14309     # . epilogue
14310     89/<- %esp 5/r32/ebp
14311     5d/pop-to-ebp
14312     c3/return
14313 
14314 check-mu-populate-stream-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
14315     # . prologue
14316     55/push-ebp
14317     89/<- %ebp 4/r32/esp
14318     # . save registers
14319 $check-mu-populate-stream-stmt:end:
14320     # . restore registers
14321     # . epilogue
14322     89/<- %esp 5/r32/ebp
14323     5d/pop-to-ebp
14324     c3/return
14325 
14326 check-mu-read-from-stream-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
14327     # . prologue
14328     55/push-ebp
14329     89/<- %ebp 4/r32/esp
14330     # . save registers
14331 $check-mu-read-from-stream-stmt:end:
14332     # . restore registers
14333     # . epilogue
14334     89/<- %esp 5/r32/ebp
14335     5d/pop-to-ebp
14336     c3/return
14337 
14338 check-mu-write-to-stream-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
14339     # . prologue
14340     55/push-ebp
14341     89/<- %ebp 4/r32/esp
14342     # . save registers
14343 $check-mu-write-to-stream-stmt:end:
14344     # . restore registers
14345     # . epilogue
14346     89/<- %esp 5/r32/ebp
14347     5d/pop-to-ebp
14348     c3/return
14349 
14350 check-mu-convert-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
14351     # . prologue
14352     55/push-ebp
14353     89/<- %ebp 4/r32/esp
14354     # . save registers
14355 $check-mu-convert-stmt:end:
14356     # . restore registers
14357     # . epilogue
14358     89/<- %esp 5/r32/ebp
14359     5d/pop-to-ebp
14360     c3/return
14361 
14362 check-mu-call:  # stmt: (addr stmt), callee: (addr function), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
14363     # . prologue
14364     55/push-ebp
14365     89/<- %ebp 4/r32/esp
14366     # var type-parameters: (addr table (handle array byte) (addr type-tree) 8)
14367     68/push 0/imm32
14368     # var type-parameters-storage: (table (handle array byte) (addr type-tree) 8)
14369     81 5/subop/subtract %esp 0x60/imm32
14370     68/push 0x60/imm32/size
14371     68/push 0/imm32/read
14372     68/push 0/imm32/write
14373     # save a pointer to type-parameters-storage at type-parameters
14374     89/<- *(ebp-4) 4/r32/esp
14375     (clear-stream *(ebp-4))
14376     # . save registers
14377     50/push-eax
14378     51/push-ecx
14379     52/push-edx
14380     53/push-ebx
14381     56/push-esi
14382     57/push-edi
14383     # esi = stmt
14384     8b/-> *(ebp+8) 6/r32/esi
14385     # edi = callee
14386     8b/-> *(ebp+0xc) 7/r32/edi
14387     # var inouts/ecx: (addr stmt-var) = lookup(stmt->inouts)
14388     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
14389     89/<- %ecx 0/r32/eax
14390     # var expected/edx: (addr list var) = lookup(f->inouts)
14391     (lookup *(edi+8) *(edi+0xc))  # Function-inouts Function-inouts => eax
14392     89/<- %edx 0/r32/eax
14393     {
14394 $check-mu-call:check-for-inouts:
14395       # if (inouts == 0) break
14396       81 7/subop/compare %ecx 0/imm32
14397       0f 84/jump-if-= break/disp32
14398       # if (expected == 0) error
14399       81 7/subop/compare %edx 0/imm32
14400       0f 84/jump-if-= break/disp32
14401 $check-mu-call:check-inout-type:
14402       # var v/eax: (addr v) = lookup(inouts->value)
14403       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
14404       # var t/ebx: (addr type-tree) = lookup(v->type)
14405       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
14406       89/<- %ebx 0/r32/eax
14407       # if (inouts->is-deref?) t = t->right  # TODO: check that t->left is an addr
14408       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
14409       {
14410         74/jump-if-= break/disp8
14411         (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
14412         89/<- %ebx 0/r32/eax
14413         # if t->right is null, t = t->left
14414         81 7/subop/compare *(ebx+0xc) 0/imm32  # Type-tree-right
14415         75/jump-if-!= break/disp8
14416         (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
14417         89/<- %ebx 0/r32/eax
14418       }
14419       # var v2/eax: (addr v) = lookup(expected->value)
14420       (lookup *edx *(edx+4))  # List-value List-value => eax
14421       # var t2/eax: (addr type-tree) = lookup(v2->type)
14422       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
14423       # if (t != t2) error
14424       (type-match? %eax %ebx *(ebp-4))  # => eax
14425       3d/compare-eax-and 0/imm32/false
14426       {
14427         0f 85/jump-if-!= break/disp32
14428         (write-buffered *(ebp+0x14) "fn ")
14429         8b/-> *(ebp+0x10) 0/r32/eax
14430         (lookup *eax *(eax+4))  # Function-name Function-name => eax
14431         (write-buffered *(ebp+0x14) %eax)
14432         (write-buffered *(ebp+0x14) ": call ")
14433         (lookup *edi *(edi+4))  # Function-name Function-name => eax
14434         (write-buffered *(ebp+0x14) %eax)
14435         (write-buffered *(ebp+0x14) ": type for inout '")
14436         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
14437         (lookup *eax *(eax+4))  # Var-name Var-name => eax
14438         (write-buffered *(ebp+0x14) %eax)
14439         (write-buffered *(ebp+0x14) "' is not right\n")
14440         (flush *(ebp+0x14))
14441         (stop *(ebp+0x18) 1)
14442       }
14443 $check-mu-call:continue-to-next-inout:
14444       # inouts = lookup(inouts->next)
14445       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
14446       89/<- %ecx 0/r32/eax
14447       # expected = lookup(expected->next)
14448       (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
14449       89/<- %edx 0/r32/eax
14450       #
14451       e9/jump loop/disp32
14452     }
14453 $check-mu-call:check-inout-count:
14454     # if (inouts == expected) proceed
14455     39/compare %ecx 2/r32/edx
14456     {
14457       0f 84/jump-if-= break/disp32
14458       # exactly one of the two is null
14459       # if (inouts == 0) error("too many inouts")
14460       {
14461         81 7/subop/compare %ecx 0/imm32
14462         0f 84/jump-if-= break/disp32
14463         (write-buffered *(ebp+0x14) "fn ")
14464         8b/-> *(ebp+0x10) 0/r32/eax
14465         (lookup *eax *(eax+4))  # Function-name Function-name => eax
14466         (write-buffered *(ebp+0x14) %eax)
14467         (write-buffered *(ebp+0x14) ": call ")
14468         (lookup *edi *(edi+4))  # Function-name Function-name => eax
14469         (write-buffered *(ebp+0x14) %eax)
14470         (write-buffered *(ebp+0x14) ": too many inouts\n")
14471         (flush *(ebp+0x14))
14472         (stop *(ebp+0x18) 1)
14473       }
14474       # if (expected == 0) error("too few inouts")
14475       {
14476         81 7/subop/compare %edx 0/imm32
14477         0f 84/jump-if-= break/disp32
14478         (write-buffered *(ebp+0x14) "fn ")
14479         8b/-> *(ebp+0x10) 0/r32/eax
14480         (lookup *eax *(eax+4))  # Function-name Function-name => eax
14481         (write-buffered *(ebp+0x14) %eax)
14482         (write-buffered *(ebp+0x14) ": call ")
14483         (lookup *edi *(edi+4))  # Function-name Function-name => eax
14484         (write-buffered *(ebp+0x14) %eax)
14485         (write-buffered *(ebp+0x14) ": too few inouts\n")
14486         (flush *(ebp+0x14))
14487         (stop *(ebp+0x18) 1)
14488       }
14489     }
14490 $check-mu-call:check-outputs:
14491     # var outputs/ecx: (addr stmt-var) = lookup(stmt->outputs)
14492     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
14493     89/<- %ecx 0/r32/eax
14494     # var expected/edx: (addr list var) = lookup(f->outputs)
14495     (lookup *(edi+0x10) *(edi+0x14))  # Function-outputs Function-outputs => eax
14496     89/<- %edx 0/r32/eax
14497     {
14498 $check-mu-call:check-for-outputs:
14499       # if (outputs == 0) break
14500       81 7/subop/compare %ecx 0/imm32
14501       0f 84/jump-if-= break/disp32
14502       # if (expected == 0) error
14503       81 7/subop/compare %edx 0/imm32
14504       0f 84/jump-if-= break/disp32
14505 $check-mu-call:check-output-type:
14506       # var v/eax: (addr v) = lookup(outputs->value)
14507       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
14508       # var t/ebx: (addr type-tree) = lookup(v->type)
14509       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
14510       89/<- %ebx 0/r32/eax
14511       # if (outputs->is-deref?) t = t->right  # TODO: check that t->left is an addr
14512       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
14513       {
14514         74/jump-if-= break/disp8
14515         (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
14516         89/<- %ebx 0/r32/eax
14517       }
14518       # var v2/eax: (addr v) = lookup(expected->value)
14519       (lookup *edx *(edx+4))  # List-value List-value => eax
14520       # var t2/eax: (addr type-tree) = lookup(v2->type)
14521       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
14522       # if (t != t2) error
14523       (type-match? %eax %ebx *(ebp-4))  # => eax
14524       3d/compare-eax-and 0/imm32/false
14525       {
14526         0f 85/jump-if-!= break/disp32
14527         (write-buffered *(ebp+0x14) "fn ")
14528         8b/-> *(ebp+0x10) 0/r32/eax
14529         (lookup *eax *(eax+4))  # Function-name Function-name => eax
14530         (write-buffered *(ebp+0x14) %eax)
14531         (write-buffered *(ebp+0x14) ": call ")
14532         (lookup *edi *(edi+4))  # Function-name Function-name => eax
14533         (write-buffered *(ebp+0x14) %eax)
14534         (write-buffered *(ebp+0x14) ": type for output '")
14535         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
14536         (lookup *eax *(eax+4))  # Var-name Var-name => eax
14537         (write-buffered *(ebp+0x14) %eax)
14538         (write-buffered *(ebp+0x14) "' is not right\n")
14539         (flush *(ebp+0x14))
14540         (stop *(ebp+0x18) 1)
14541       }
14542 $check-mu-call:check-output-register:
14543       # var v/eax: (addr v) = lookup(outputs->value)
14544       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
14545       # var r/ebx: (addr array byte) = lookup(v->register)
14546       (lookup *(eax+18) *(eax+0x1c))  # Var-register Var-register => eax
14547       89/<- %ebx 0/r32/eax
14548       # if (r == 0) error
14549       3d/compare-eax-and 0/imm32
14550       {
14551         0f 85/jump-if-!= break/disp32
14552         (write-buffered *(ebp+0x14) "fn ")
14553         8b/-> *(ebp+0x10) 0/r32/eax
14554         (lookup *eax *(eax+4))  # Function-name Function-name => eax
14555         (write-buffered *(ebp+0x14) %eax)
14556         (write-buffered *(ebp+0x14) ": call ")
14557         (lookup *edi *(edi+4))  # Function-name Function-name => eax
14558         (write-buffered *(ebp+0x14) %eax)
14559         (write-buffered *(ebp+0x14) ": output '")
14560         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
14561         (lookup *eax *(eax+4))  # Var-name Var-name => eax
14562         (write-buffered *(ebp+0x14) %eax)
14563         (write-buffered *(ebp+0x14) "' is not in a register\n")
14564         (flush *(ebp+0x14))
14565         (stop *(ebp+0x18) 1)
14566       }
14567       # var v2/eax: (addr v) = lookup(expected->value)
14568       (lookup *edx *(edx+4))  # Stmt-var-value Stmt-var-value => eax
14569       # var r2/eax: (addr array byte) = lookup(v2->register)
14570       (lookup *(eax+18) *(eax+0x1c))  # Var-register Var-register => eax
14571       # if (r != r2) error
14572       (string-equal? %eax %ebx)  # => eax
14573       3d/compare-eax-and 0/imm32/false
14574       {
14575         0f 85/jump-if-!= break/disp32
14576         (write-buffered *(ebp+0x14) "fn ")
14577         8b/-> *(ebp+0x10) 0/r32/eax
14578         (lookup *eax *(eax+4))  # Function-name Function-name => eax
14579         (write-buffered *(ebp+0x14) %eax)
14580         (write-buffered *(ebp+0x14) ": call ")
14581         (lookup *edi *(edi+4))  # Function-name Function-name => eax
14582         (write-buffered *(ebp+0x14) %eax)
14583         (write-buffered *(ebp+0x14) ": register for output '")
14584         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
14585         (lookup *eax *(eax+4))  # Var-name Var-name => eax
14586         (write-buffered *(ebp+0x14) %eax)
14587         (write-buffered *(ebp+0x14) "' is not right\n")
14588         (flush *(ebp+0x14))
14589         (stop *(ebp+0x18) 1)
14590       }
14591 $check-mu-call:continue-to-next-output:
14592       # outputs = lookup(outputs->next)
14593       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
14594       89/<- %ecx 0/r32/eax
14595       # expected = lookup(expected->next)
14596       (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
14597       89/<- %edx 0/r32/eax
14598       #
14599       e9/jump loop/disp32
14600     }
14601 $check-mu-call:check-output-count:
14602     # if (outputs == expected) proceed
14603     39/compare %ecx 2/r32/edx
14604     {
14605       0f 84/jump-if-= break/disp32
14606       # exactly one of the two is null
14607       # if (outputs == 0) error("too many outputs")
14608       {
14609         81 7/subop/compare %ecx 0/imm32
14610         0f 84/jump-if-= break/disp32
14611         (write-buffered *(ebp+0x14) "fn ")
14612         8b/-> *(ebp+0x10) 0/r32/eax
14613         (lookup *eax *(eax+4))  # Function-name Function-name => eax
14614         (write-buffered *(ebp+0x14) %eax)
14615         (write-buffered *(ebp+0x14) ": call ")
14616         (lookup *edi *(edi+4))  # Function-name Function-name => eax
14617         (write-buffered *(ebp+0x14) %eax)
14618         (write-buffered *(ebp+0x14) ": too many outputs\n")
14619         (flush *(ebp+0x14))
14620         (stop *(ebp+0x18) 1)
14621       }
14622       # if (expected == 0) error("too few outputs")
14623       {
14624         81 7/subop/compare %edx 0/imm32
14625         0f 84/jump-if-= break/disp32
14626         (write-buffered *(ebp+0x14) "fn ")
14627         8b/-> *(ebp+0x10) 0/r32/eax
14628         (lookup *eax *(eax+4))  # Function-name Function-name => eax
14629         (write-buffered *(ebp+0x14) %eax)
14630         (write-buffered *(ebp+0x14) ": call ")
14631         (lookup *edi *(edi+4))  # Function-name Function-name => eax
14632         (write-buffered *(ebp+0x14) %eax)
14633         (write-buffered *(ebp+0x14) ": too few outputs\n")
14634         (flush *(ebp+0x14))
14635         (stop *(ebp+0x18) 1)
14636       }
14637     }
14638 $check-mu-call:end:
14639     # . restore registers
14640     5f/pop-to-edi
14641     5e/pop-to-esi
14642     5b/pop-to-ebx
14643     5a/pop-to-edx
14644     59/pop-to-ecx
14645     58/pop-to-eax
14646     # . reclaim locals exclusively on the stack
14647     81 0/subop/add %esp 0x70/imm32
14648     # . epilogue
14649     89/<- %esp 5/r32/ebp
14650     5d/pop-to-ebp
14651     c3/return
14652 
14653 # like type-equal? but takes literals into account
14654 type-match?:  # def: (addr type-tree), call: (addr type-tree), type-parameters: (addr table (handle array byte) (addr type-tree)) -> result/eax: boolean
14655     # . prologue
14656     55/push-ebp
14657     89/<- %ebp 4/r32/esp
14658     # if (call == literal) return true  # TODO: more precise
14659     (is-simple-mu-type? *(ebp+0xc) 0)  # literal => eax
14660     3d/compare-eax-and 0/imm32/false
14661     b8/copy-to-eax 1/imm32/true
14662     75/jump-if-!= $type-match?:end/disp8
14663 $type-match?:baseline:
14664     # otherwise fall back
14665     (type-component-match? *(ebp+8) *(ebp+0xc) *(ebp+0x10))  # => eax
14666 $type-match?:end:
14667     # . epilogue
14668     89/<- %esp 5/r32/ebp
14669     5d/pop-to-ebp
14670     c3/return
14671 
14672 type-component-match?:  # def: (addr type-tree), call: (addr type-tree), type-parameters: (addr table (handle array byte) (addr type-tree)) -> result/eax: boolean
14673     # . prologue
14674     55/push-ebp
14675     89/<- %ebp 4/r32/esp
14676     # . save registers
14677     51/push-ecx
14678     52/push-edx
14679     53/push-ebx
14680     # ecx = def
14681     8b/-> *(ebp+8) 1/r32/ecx
14682     # edx = call
14683     8b/-> *(ebp+0xc) 2/r32/edx
14684 $type-component-match?:compare-addr:
14685     # if (def == call) return true
14686     8b/-> %ecx 0/r32/eax  # Var-type
14687     39/compare %edx 0/r32/eax  # Var-type
14688     b8/copy-to-eax 1/imm32/true
14689     0f 84/jump-if-= $type-component-match?:end/disp32
14690     # if (def == 0) return false
14691     b8/copy-to-eax 0/imm32/false
14692     81 7/subop/compare %ecx 0/imm32  # Type-tree-is-atom
14693     0f 84/jump-if-= $type-component-match?:end/disp32
14694     # if (call == 0) return false
14695     81 7/subop/compare %edx 0/imm32  # Type-tree-is-atom
14696     0f 84/jump-if-= $type-component-match?:end/disp32
14697     # if def is a type parameter, just check in type-parameters
14698     {
14699 $type-component-match?:check-type-parameter:
14700       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
14701       74/jump-if-= break/disp8
14702       81 7/subop/compare *(ecx+4) 0xa/imm32/type-parameter  # Type-tree-value
14703       75/jump-if-!= break/disp8
14704 $type-component-match?:type-parameter:
14705       (type-parameter-match? *(ecx+8) *(ecx+0xc)  %edx  *(ebp+0x10))  # => eax
14706       e9/jump $type-component-match?:end/disp32
14707     }
14708     # if def is a list containing just a type parameter, just check in type-parameters
14709     {
14710 $type-component-match?:check-list-type-parameter:
14711       # if def is a list..
14712       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
14713       75/jump-if-!= break/disp8
14714       #   ..that's a singleton
14715       81 7/subop/compare *(ecx+0xc) 0/imm32  # Type-tree-left
14716       75/jump-if-!= break/disp8
14717       #   ..and whose head is a type parameter
14718       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14719       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14720       74/jump-if-= break/disp8
14721       81 7/subop/compare *(eax+4) 0xa/imm32/type-parameter  # Type-tree-value
14722       75/jump-if-!= break/disp8
14723 $type-component-match?:list-type-parameter:
14724       (type-parameter-match? *(eax+8) *(eax+0xc)  %edx  *(ebp+0x10))  # => eax
14725       e9/jump $type-component-match?:end/disp32
14726     }
14727 $type-component-match?:compare-atom-state:
14728     # if (def->is-atom? != call->is-atom?) return false
14729     8b/-> *ecx 3/r32/ebx  # Type-tree-is-atom
14730     39/compare *edx 3/r32/ebx  # Type-tree-is-atom
14731     b8/copy-to-eax 0/imm32/false
14732     0f 85/jump-if-!= $type-component-match?:end/disp32
14733     # if def->is-atom? return (def->value == call->value)
14734     {
14735 $type-component-match?:check-atom:
14736       81 7/subop/compare %ebx 0/imm32/false
14737       74/jump-if-= break/disp8
14738 $type-component-match?:is-atom:
14739       8b/-> *(ecx+4) 0/r32/eax  # Type-tree-value
14740       39/compare *(edx+4) 0/r32/eax  # Type-tree-value
14741       0f 94/set-if-= %al
14742       81 4/subop/and %eax 0xff/imm32
14743       e9/jump $type-component-match?:end/disp32
14744     }
14745 $type-component-match?:check-left:
14746     # if (!type-component-match?(def->left, call->left)) return false
14747     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14748     89/<- %ebx 0/r32/eax
14749     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
14750     (type-component-match? %ebx %eax *(ebp+0x10))  # => eax
14751     3d/compare-eax-and 0/imm32/false
14752     74/jump-if-= $type-component-match?:end/disp8
14753 $type-component-match?:check-right:
14754     # return type-component-match?(def->right, call->right)
14755     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
14756     89/<- %ebx 0/r32/eax
14757     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
14758     (type-component-match? %ebx %eax *(ebp+0x10))  # => eax
14759 $type-component-match?:end:
14760     # . restore registers
14761     5b/pop-to-ebx
14762     5a/pop-to-edx
14763     59/pop-to-ecx
14764     # . epilogue
14765     89/<- %esp 5/r32/ebp
14766     5d/pop-to-ebp
14767     c3/return
14768 
14769 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
14770     # . prologue
14771     55/push-ebp
14772     89/<- %ebp 4/r32/esp
14773     # . save registers
14774     51/push-ecx
14775     #
14776     (get-or-insert-handle *(ebp+0x14)  *(ebp+8) *(ebp+0xc)  0xc)  # => eax
14777     # if parameter wasn't saved, save it
14778     {
14779       81 7/subop/compare *eax 0/imm32
14780       75/jump-if-!= break/disp8
14781       8b/-> *(ebp+0x10) 1/r32/ecx
14782       89/<- *eax 1/r32/ecx
14783     }
14784     #
14785     (type-equal? *(ebp+0x10) *eax)  # => eax
14786 $type-parameter-match?:end:
14787     # . restore registers
14788     59/pop-to-ecx
14789     # . epilogue
14790     89/<- %esp 5/r32/ebp
14791     5d/pop-to-ebp
14792     c3/return
14793 
14794 size-of:  # v: (addr var) -> result/eax: int
14795     # . prologue
14796     55/push-ebp
14797     89/<- %ebp 4/r32/esp
14798     # . save registers
14799     51/push-ecx
14800     # var t/ecx: (addr type-tree) = lookup(v->type)
14801     8b/-> *(ebp+8) 1/r32/ecx
14802 #?     (write-buffered Stderr "size-of ")
14803 #?     (write-int32-hex-buffered Stderr %ecx)
14804 #?     (write-buffered Stderr Newline)
14805 #?     (write-buffered Stderr "type allocid: ")
14806 #?     (write-int32-hex-buffered Stderr *(ecx+8))
14807 #?     (write-buffered Stderr Newline)
14808 #?     (flush Stderr)
14809     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
14810     89/<- %ecx 0/r32/eax
14811     # if is-mu-array?(t) return size-of-array(t)
14812     {
14813       (is-mu-array? %ecx)  # => eax
14814       3d/compare-eax-and 0/imm32/false
14815       74/jump-if-= break/disp8
14816       (size-of-array %ecx)  # => eax
14817       eb/jump $size-of:end/disp8
14818     }
14819     # if is-mu-stream?(t) return size-of-stream(t)
14820     {
14821       (is-mu-stream? %ecx)  # => eax
14822       3d/compare-eax-and 0/imm32/false
14823       74/jump-if-= break/disp8
14824       (size-of-stream %ecx)  # => eax
14825       eb/jump $size-of:end/disp8
14826     }
14827     # if (!t->is-atom?) t = lookup(t->left)
14828     {
14829       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
14830       75/jump-if-!= break/disp8
14831       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14832       89/<- %ecx 0/r32/eax
14833     }
14834     # TODO: assert t->is-atom?
14835     (size-of-type-id *(ecx+4))  # Type-tree-value => eax
14836 $size-of:end:
14837     # . restore registers
14838     59/pop-to-ecx
14839     # . epilogue
14840     89/<- %esp 5/r32/ebp
14841     5d/pop-to-ebp
14842     c3/return
14843 
14844 size-of-deref:  # v: (addr var) -> result/eax: int
14845     # . prologue
14846     55/push-ebp
14847     89/<- %ebp 4/r32/esp
14848     # . save registers
14849     51/push-ecx
14850     # var t/ecx: (addr type-tree) = lookup(v->type)
14851     8b/-> *(ebp+8) 1/r32/ecx
14852     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
14853     89/<- %ecx 0/r32/eax
14854     # TODO: assert(t is an addr)
14855     # t = lookup(t->right)
14856     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
14857     89/<- %ecx 0/r32/eax
14858     # if is-mu-array?(t) return size-of-array(t)
14859     {
14860       (is-mu-array? %ecx)  # => eax
14861       3d/compare-eax-and 0/imm32/false
14862       74/jump-if-= break/disp8
14863       (size-of-array %ecx)  # => eax
14864       eb/jump $size-of-deref:end/disp8
14865     }
14866     # if is-mu-stream?(t) return size-of-stream(t)
14867     {
14868       (is-mu-stream? %ecx)  # => eax
14869       3d/compare-eax-and 0/imm32/false
14870       74/jump-if-= break/disp8
14871       (size-of-stream %ecx)  # => eax
14872       eb/jump $size-of-deref:end/disp8
14873     }
14874     # if (!t->is-atom?) t = lookup(t->left)
14875     {
14876       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
14877       75/jump-if-!= break/disp8
14878       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14879       89/<- %ecx 0/r32/eax
14880     }
14881     # TODO: assert t->is-atom?
14882     (size-of-type-id *(ecx+4))  # Type-tree-value => eax
14883 $size-of-deref:end:
14884     # . restore registers
14885     59/pop-to-ecx
14886     # . epilogue
14887     89/<- %esp 5/r32/ebp
14888     5d/pop-to-ebp
14889     c3/return
14890 
14891 is-mu-array?:  # t: (addr type-tree) -> result/eax: boolean
14892     # . prologue
14893     55/push-ebp
14894     89/<- %ebp 4/r32/esp
14895     # . save registers
14896     51/push-ecx
14897     # ecx = t
14898     8b/-> *(ebp+8) 1/r32/ecx
14899     # if t->is-atom?, return false
14900     81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
14901     75/jump-if-!= $is-mu-array?:return-false/disp8
14902     # if !t->left->is-atom?, return false
14903     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14904     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14905     74/jump-if-= $is-mu-array?:return-false/disp8
14906     # return t->left->value == array
14907     81 7/subop/compare *(eax+4) 3/imm32/array-type-id  # Type-tree-value
14908     0f 94/set-if-= %al
14909     81 4/subop/and %eax 0xff/imm32
14910     eb/jump $is-mu-array?:end/disp8
14911 $is-mu-array?:return-false:
14912     b8/copy-to-eax 0/imm32/false
14913 $is-mu-array?:end:
14914     # . restore registers
14915     59/pop-to-ecx
14916     # . epilogue
14917     89/<- %esp 5/r32/ebp
14918     5d/pop-to-ebp
14919     c3/return
14920 
14921 # size of a statically allocated array where the size is part of the type expression
14922 size-of-array:  # a: (addr type-tree) -> result/eax: int
14923     # . prologue
14924     55/push-ebp
14925     89/<- %ebp 4/r32/esp
14926     # . save registers
14927     51/push-ecx
14928     52/push-edx
14929     #
14930     8b/-> *(ebp+8) 1/r32/ecx
14931     # TODO: assert that a->left is 'array'
14932     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
14933     89/<- %ecx 0/r32/eax
14934     # var elem-type/edx: type-id = a->right->left->value
14935     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14936     8b/-> *(eax+4) 2/r32/edx  # Type-tree-value
14937     # TODO: assert that a->right->right->left->value == size
14938     # var array-size/ecx: int = a->right->right->left->value-size
14939     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
14940     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
14941     8b/-> *(eax+8) 1/r32/ecx  # Type-tree-value-size
14942     # return 4 + array-size * size-of(elem-type)
14943     (size-of-type-id-as-array-element %edx)  # => eax
14944     f7 4/subop/multiply-into-edx-eax %ecx
14945     05/add-to-eax 4/imm32  # for array size
14946     # TODO: check edx for overflow
14947 $size-of-array:end:
14948     # . restore registers
14949     5a/pop-to-edx
14950     59/pop-to-ecx
14951     # . epilogue
14952     89/<- %esp 5/r32/ebp
14953     5d/pop-to-ebp
14954     c3/return
14955 
14956 is-mu-stream?:  # t: (addr type-tree) -> result/eax: boolean
14957     # . prologue
14958     55/push-ebp
14959     89/<- %ebp 4/r32/esp
14960     # . save registers
14961     51/push-ecx
14962     # ecx = t
14963     8b/-> *(ebp+8) 1/r32/ecx
14964     # if t->is-atom?, return false
14965     81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
14966     75/jump-if-!= $is-mu-stream?:return-false/disp8
14967     # if !t->left->is-atom?, return false
14968     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14969     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14970     74/jump-if-= $is-mu-stream?:return-false/disp8
14971     # return t->left->value == stream
14972     81 7/subop/compare *(eax+4) 0xb/imm32/stream-type-id  # Type-tree-value
14973     0f 94/set-if-= %al
14974     81 4/subop/and %eax 0xff/imm32
14975     eb/jump $is-mu-stream?:end/disp8
14976 $is-mu-stream?:return-false:
14977     b8/copy-to-eax 0/imm32/false
14978 $is-mu-stream?:end:
14979     # . restore registers
14980     59/pop-to-ecx
14981     # . epilogue
14982     89/<- %esp 5/r32/ebp
14983     5d/pop-to-ebp
14984     c3/return
14985 
14986 # size of a statically allocated stream where the size is part of the type expression
14987 size-of-stream:  # a: (addr type-tree) -> result/eax: int
14988     # . prologue
14989     55/push-ebp
14990     89/<- %ebp 4/r32/esp
14991     #
14992     (size-of-array *(ebp+8))  # assumes we ignore the actual type name 'array' in the type
14993     05/add-to-eax 8/imm32  # for read/write pointers
14994 $size-of-stream:end:
14995     # . epilogue
14996     89/<- %esp 5/r32/ebp
14997     5d/pop-to-ebp
14998     c3/return
14999 
15000 size-of-type-id:  # t: type-id -> result/eax: int
15001     # . prologue
15002     55/push-ebp
15003     89/<- %ebp 4/r32/esp
15004     # . save registers
15005     51/push-ecx
15006     # var out/ecx: (handle typeinfo)
15007     68/push 0/imm32
15008     68/push 0/imm32
15009     89/<- %ecx 4/r32/esp
15010     # eax = t
15011     8b/-> *(ebp+8) 0/r32/eax
15012     # if t is a literal, return 0
15013     3d/compare-eax-and 0/imm32
15014     0f 84/jump-if-= $size-of-type-id:end/disp32  # eax changes type from type-id to int
15015     # if t is a byte, return 4 (because we don't really support non-multiples of 4)
15016     3d/compare-eax-and 8/imm32/byte
15017     {
15018       75/jump-if-!= break/disp8
15019       b8/copy-to-eax 4/imm32
15020       eb/jump $size-of-type-id:end/disp8
15021     }
15022     # if t is a handle, return 8
15023     3d/compare-eax-and 4/imm32/handle
15024     {
15025       75/jump-if-!= break/disp8
15026       b8/copy-to-eax 8/imm32
15027       eb/jump $size-of-type-id:end/disp8  # eax changes type from type-id to int
15028     }
15029     # if t is a slice, return 8
15030     3d/compare-eax-and 0xc/imm32/slice
15031     {
15032       75/jump-if-!= break/disp8
15033       b8/copy-to-eax 8/imm32
15034       eb/jump $size-of-type-id:end/disp8  # eax changes type from type-id to int
15035     }
15036     # if t is a user-defined type, return its size
15037     # TODO: support non-atom type
15038     (find-typeinfo %eax %ecx)
15039     {
15040       81 7/subop/compare *ecx 0/imm32
15041       74/jump-if-= break/disp8
15042 $size-of-type-id:user-defined:
15043       (lookup *ecx *(ecx+4))  # => eax
15044       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
15045       eb/jump $size-of-type-id:end/disp8
15046     }
15047     # otherwise return the word size
15048     b8/copy-to-eax 4/imm32
15049 $size-of-type-id:end:
15050     # . reclaim locals
15051     81 0/subop/add %esp 8/imm32
15052     # . restore registers
15053     59/pop-to-ecx
15054     # . epilogue
15055     89/<- %esp 5/r32/ebp
15056     5d/pop-to-ebp
15057     c3/return
15058 
15059 # Minor violation of our type system since it returns an addr. But we could
15060 # replace it with a handle some time.
15061 # Returns null if t is an atom.
15062 type-tail:  # t: (addr type-tree) -> out/eax: (addr type-tree)
15063     # . prologue
15064     55/push-ebp
15065     89/<- %ebp 4/r32/esp
15066     # . save registers
15067     51/push-ecx
15068     # eax = 0
15069     b8/copy-to-eax 0/imm32
15070     # ecx = t
15071     8b/-> *(ebp+8) 1/r32/ecx
15072 $type-tail:check-atom:
15073     # if t->is-atom? return 0
15074     81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
15075     0f 85/jump-if-!= $type-tail:end/disp32
15076     # var tail = t->right
15077     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
15078     89/<- %ecx 0/r32/eax
15079 $type-tail:check-singleton:
15080     # if (tail->right == 0) return tail->left
15081     {
15082       81 7/subop/compare *(ecx+0xc) 0/imm32  # Type-tree-right
15083       75/jump-if-!= break/disp8
15084       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
15085       e9/jump $type-tail:end/disp32
15086     }
15087     # if tail->right->left is an array-capacity, return tail->left
15088     {
15089 $type-tail:check-array-capacity:
15090       (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
15091       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
15092       75/jump-if-!= break/disp8
15093 $type-tail:check-array-capacity-1:
15094       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
15095       3d/compare-eax-and 0/imm32
15096       74/jump-if-= break/disp8
15097 $type-tail:check-array-capacity-2:
15098       (is-simple-mu-type? %eax 9)  # array-capacity => eax
15099       3d/compare-eax-and 0/imm32/false
15100       74/jump-if-= break/disp8
15101 $type-tail:array-capacity:
15102       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
15103       eb/jump $type-tail:end/disp8
15104     }
15105 $type-tail:check-compound-left:
15106     # if !tail->left->is-atom? return tail->left
15107     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
15108     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
15109     74/jump-if-= $type-tail:end/disp8
15110 $type-tail:return-tail:
15111     # return tail
15112     89/<- %eax 1/r32/ecx
15113 $type-tail:end:
15114     # . restore registers
15115     59/pop-to-ecx
15116     # . epilogue
15117     89/<- %esp 5/r32/ebp
15118     5d/pop-to-ebp
15119     c3/return
15120 
15121 type-equal?:  # a: (addr type-tree), b: (addr type-tree) -> result/eax: boolean
15122     # . prologue
15123     55/push-ebp
15124     89/<- %ebp 4/r32/esp
15125     # . save registers
15126     51/push-ecx
15127     52/push-edx
15128     53/push-ebx
15129     # ecx = a
15130     8b/-> *(ebp+8) 1/r32/ecx
15131     # edx = b
15132     8b/-> *(ebp+0xc) 2/r32/edx
15133 $type-equal?:compare-addr:
15134     # if (a == b) return true
15135     8b/-> %ecx 0/r32/eax  # Var-type
15136     39/compare %edx 0/r32/eax  # Var-type
15137     b8/copy-to-eax 1/imm32/true
15138     0f 84/jump-if-= $type-equal?:end/disp32
15139 $type-equal?:compare-null-a:
15140     # if (a == 0) return false
15141     b8/copy-to-eax 0/imm32/false
15142     81 7/subop/compare %ecx 0/imm32
15143     0f 84/jump-if-= $type-equal?:end/disp32
15144 $type-equal?:compare-null-b:
15145     # if (b == 0) return false
15146     81 7/subop/compare %edx 0/imm32
15147     0f 84/jump-if-= $type-equal?:end/disp32
15148 $type-equal?:compare-atom-state:
15149     # if (a->is-atom? != b->is-atom?) return false
15150     8b/-> *ecx 3/r32/ebx  # Type-tree-is-atom
15151     39/compare *edx 3/r32/ebx  # Type-tree-is-atom
15152     b8/copy-to-eax 0/imm32/false
15153     0f 85/jump-if-!= $type-equal?:end/disp32
15154     # if a->is-atom? return (a->value == b->value)
15155     {
15156 $type-equal?:check-atom:
15157       81 7/subop/compare %ebx 0/imm32/false
15158       74/jump-if-= break/disp8
15159 $type-equal?:is-atom:
15160       8b/-> *(ecx+4) 0/r32/eax  # Type-tree-value
15161       39/compare *(edx+4) 0/r32/eax  # Type-tree-value
15162       0f 94/set-if-= %al
15163       81 4/subop/and %eax 0xff/imm32
15164       e9/jump $type-equal?:end/disp32
15165     }
15166 $type-equal?:check-left:
15167     # if (!type-equal?(a->left, b->left)) return false
15168     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
15169     89/<- %ebx 0/r32/eax
15170     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
15171     (type-equal? %eax %ebx)  # => eax
15172     3d/compare-eax-and 0/imm32/false
15173     74/jump-if-= $type-equal?:end/disp8
15174 $type-equal?:check-right:
15175     # return type-equal?(a->right, b->right)
15176     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
15177     89/<- %ebx 0/r32/eax
15178     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
15179     (type-equal? %eax %ebx)  # => eax
15180 $type-equal?:end:
15181     # . restore registers
15182     5b/pop-to-ebx
15183     5a/pop-to-edx
15184     59/pop-to-ecx
15185     # . epilogue
15186     89/<- %esp 5/r32/ebp
15187     5d/pop-to-ebp
15188     c3/return
15189 
15190 #######################################################
15191 # Code-generation
15192 #######################################################
15193 
15194 == data
15195 
15196 # Global state added to each var record when performing code-generation.
15197 Curr-local-stack-offset:  # (addr int)
15198     0/imm32
15199 
15200 == code
15201 
15202 emit-subx:  # out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
15203     # . prologue
15204     55/push-ebp
15205     89/<- %ebp 4/r32/esp
15206     # . save registers
15207     50/push-eax
15208     # var curr/eax: (addr function) = *Program->functions
15209     (lookup *_Program-functions *_Program-functions->payload)  # => eax
15210     {
15211       # if (curr == null) break
15212       3d/compare-eax-and 0/imm32
15213       0f 84/jump-if-= break/disp32
15214       (emit-subx-function *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))
15215       # curr = lookup(curr->next)
15216       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
15217       e9/jump loop/disp32
15218     }
15219 $emit-subx:end:
15220     # . restore registers
15221     58/pop-to-eax
15222     # . epilogue
15223     89/<- %esp 5/r32/ebp
15224     5d/pop-to-ebp
15225     c3/return
15226 
15227 emit-subx-function:  # out: (addr buffered-file), f: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
15228     # . prologue
15229     55/push-ebp
15230     89/<- %ebp 4/r32/esp
15231     # some preprocessing
15232     (populate-mu-type-offsets-in-inouts *(ebp+0xc))
15233     # . save registers
15234     50/push-eax
15235     51/push-ecx
15236     52/push-edx
15237     # initialize some global state
15238     c7 0/subop/copy *Curr-block-depth 1/imm32  # Important: keep this in sync with the parse phase
15239     c7 0/subop/copy *Curr-local-stack-offset 0/imm32
15240     # ecx = f
15241     8b/-> *(ebp+0xc) 1/r32/ecx
15242     # var vars/edx: (stack (addr var) 256)
15243     81 5/subop/subtract %esp 0xc00/imm32
15244     68/push 0xc00/imm32/size
15245     68/push 0/imm32/top
15246     89/<- %edx 4/r32/esp
15247     # var name/eax: (addr array byte) = lookup(f->name)
15248     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
15249     #
15250     (write-buffered *(ebp+8) %eax)
15251     (write-buffered *(ebp+8) ":\n")
15252     (emit-subx-prologue *(ebp+8))
15253     # var body/eax: (addr block) = lookup(f->body)
15254     (lookup *(ecx+0x18) *(ecx+0x1c))  # Function-body Function-body => eax
15255     #
15256     (emit-subx-block *(ebp+8) %eax %edx *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
15257     (emit-subx-epilogue *(ebp+8))
15258     # TODO: validate that *Curr-block-depth and *Curr-local-stack-offset have
15259     # been cleaned up
15260 $emit-subx-function:end:
15261     # . reclaim locals
15262     81 0/subop/add %esp 0xc08/imm32
15263     # . restore registers
15264     5a/pop-to-edx
15265     59/pop-to-ecx
15266     58/pop-to-eax
15267     # . epilogue
15268     89/<- %esp 5/r32/ebp
15269     5d/pop-to-ebp
15270     c3/return
15271 
15272 populate-mu-type-offsets-in-inouts:  # f: (addr function)
15273     # . prologue
15274     55/push-ebp
15275     89/<- %ebp 4/r32/esp
15276     # . save registers
15277     50/push-eax
15278     51/push-ecx
15279     52/push-edx
15280     53/push-ebx
15281     57/push-edi
15282     # var next-offset/edx: int = 8
15283     ba/copy-to-edx 8/imm32
15284     # var curr/ecx: (addr list var) = lookup(f->inouts)
15285     8b/-> *(ebp+8) 1/r32/ecx
15286     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
15287     89/<- %ecx 0/r32/eax
15288     {
15289 $populate-mu-type-offsets-in-inouts:loop:
15290       81 7/subop/compare %ecx 0/imm32
15291       74/jump-if-= break/disp8
15292       # var v/ebx: (addr var) = lookup(curr->value)
15293       (lookup *ecx *(ecx+4))  # List-value List-value => eax
15294       89/<- %ebx 0/r32/eax
15295 #?       (lookup *ebx *(ebx+4))
15296 #?       (write-buffered Stderr "setting offset of fn inout ")
15297 #?       (write-buffered Stderr %eax)
15298 #?       (write-buffered Stderr "@")
15299 #?       (write-int32-hex-buffered Stderr %ebx)
15300 #?       (write-buffered Stderr " to ")
15301 #?       (write-int32-hex-buffered Stderr %edx)
15302 #?       (write-buffered Stderr Newline)
15303 #?       (flush Stderr)
15304       # v->offset = next-offset
15305       89/<- *(ebx+0x14) 2/r32/edx  # Var-offset
15306       # next-offset += size-of(v)
15307       (size-of %ebx)  # => eax
15308       01/add-to %edx 0/r32/eax
15309       # curr = lookup(curr->next)
15310       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
15311       89/<- %ecx 0/r32/eax
15312       #
15313       eb/jump loop/disp8
15314     }
15315 $populate-mu-type-offsets-in-inouts:end:
15316     # . restore registers
15317     5f/pop-to-edi
15318     5b/pop-to-ebx
15319     5a/pop-to-edx
15320     59/pop-to-ecx
15321     58/pop-to-eax
15322     # . epilogue
15323     89/<- %esp 5/r32/ebp
15324     5d/pop-to-ebp
15325     c3/return
15326 
15327 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)
15328     # . prologue
15329     55/push-ebp
15330     89/<- %ebp 4/r32/esp
15331     # . save registers
15332     50/push-eax
15333     51/push-ecx
15334     53/push-ebx
15335     56/push-esi
15336     # esi = stmts
15337     8b/-> *(ebp+0xc) 6/r32/esi
15338     #
15339     {
15340 $emit-subx-stmt-list:loop:
15341       81 7/subop/compare %esi 0/imm32
15342       0f 84/jump-if-= break/disp32
15343       # var curr-stmt/ecx: (addr stmt) = lookup(stmts->value)
15344       (lookup *esi *(esi+4))  # List-value List-value => eax
15345       89/<- %ecx 0/r32/eax
15346       {
15347 $emit-subx-stmt-list:check-for-block:
15348         81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
15349         75/jump-if-!= break/disp8
15350 $emit-subx-stmt-list:block:
15351         (emit-subx-block *(ebp+8) %ecx *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
15352       }
15353       {
15354 $emit-subx-stmt-list:check-for-stmt:
15355         81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
15356         0f 85/jump-if-!= break/disp32
15357 $emit-subx-stmt-list:stmt1:
15358         {
15359           (is-mu-branch? %ecx)  # => eax
15360           3d/compare-eax-and 0/imm32/false
15361           0f 84/jump-if-= break/disp32
15362 $emit-subx-stmt-list:branch-stmt:
15363 +-- 27 lines: # unconditional loops --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
15390 +-- 16 lines: # unconditional breaks -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
15406 +-- 38 lines: # simple conditional branches without a target -------------------------------------------------------------------------------------------------------------------------------------------------------
15444 +-- 19 lines: # conditional branches with an explicit target -------------------------------------------------------------------------------------------------------------------------------------------------------
15463         }
15464 $emit-subx-stmt-list:1-to-1:
15465         (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x18) *(ebp+0x1c))
15466         e9/jump $emit-subx-stmt-list:continue/disp32
15467       }
15468       {
15469 $emit-subx-stmt-list:check-for-var-def:
15470         81 7/subop/compare *ecx 2/imm32/var-def  # Stmt-tag
15471         75/jump-if-!= break/disp8
15472 $emit-subx-stmt-list:var-def:
15473         (emit-subx-var-def *(ebp+8) %ecx)
15474         (push *(ebp+0x10) *(ecx+4))  # Vardef-var
15475         (push *(ebp+0x10) *(ecx+8))  # Vardef-var
15476         (push *(ebp+0x10) 0)  # Live-var-register-spilled = 0 for vars on the stack
15477         #
15478         eb/jump $emit-subx-stmt-list:continue/disp8
15479       }
15480       {
15481 $emit-subx-stmt-list:check-for-reg-var-def:
15482         81 7/subop/compare *ecx 3/imm32/reg-var-def  # Stmt-tag
15483         0f 85/jump-if-!= break/disp32
15484 $emit-subx-stmt-list:reg-var-def:
15485         # TODO: ensure that there's exactly one output
15486         (push-output-and-maybe-emit-spill *(ebp+8) %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
15487         # emit the instruction as usual
15488         (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x18) *(ebp+0x1c))
15489         #
15490         eb/jump $emit-subx-stmt-list:continue/disp8
15491       }
15492 $emit-subx-stmt-list:continue:
15493       # TODO: raise an error on unrecognized Stmt-tag
15494       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
15495       89/<- %esi 0/r32/eax
15496       e9/jump loop/disp32
15497     }
15498 $emit-subx-stmt-list:emit-cleanup:
15499     (emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth)
15500 $emit-subx-stmt-list:clean-up:
15501     (clean-up-stack-offset-state *(ebp+0x10) *Curr-block-depth)
15502     (clean-up-blocks *(ebp+0x10) *Curr-block-depth *(ebp+0x14))
15503 $emit-subx-stmt-list:end:
15504     # . restore registers
15505     5e/pop-to-esi
15506     5b/pop-to-ebx
15507     59/pop-to-ecx
15508     58/pop-to-eax
15509     # . epilogue
15510     89/<- %esp 5/r32/ebp
15511     5d/pop-to-ebp
15512     c3/return
15513 
15514 # 'later-stmts' includes 'stmt', but will behave the same even without it; reg-var-def stmts are guaranteed not to write to function outputs.
15515 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)
15516     # . prologue
15517     55/push-ebp
15518     89/<- %ebp 4/r32/esp
15519     # . save registers
15520     50/push-eax
15521     51/push-ecx
15522     52/push-edx
15523     # ecx = stmt
15524     8b/-> *(ebp+0xc) 1/r32/ecx
15525     # var sv/eax: (addr stmt-var) = lookup(curr-stmt->outputs)
15526     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
15527     # TODO: assert !sv->is-deref?
15528     # var v/ecx: (addr var) = lookup(sv->value)
15529     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15530     89/<- %ecx 0/r32/eax
15531     # v->block-depth = *Curr-block-depth
15532     8b/-> *Curr-block-depth 0/r32/eax
15533     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
15534 #?     (write-buffered Stderr "var ")
15535 #?     (lookup *ecx *(ecx+4))
15536 #?     (write-buffered Stderr %eax)
15537 #?     (write-buffered Stderr " at depth ")
15538 #?     (write-int32-hex-buffered Stderr *(ecx+0x10))
15539 #?     (write-buffered Stderr Newline)
15540 #?     (flush Stderr)
15541     # ensure that v is in a register
15542     81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
15543     0f 84/jump-if-= $push-output-and-maybe-emit-spill:abort/disp32
15544     # var emit-spill?/edx: boolean = not-yet-spilled-this-block? && will-not-write-some-register?(fn)
15545     (not-yet-spilled-this-block? %ecx *(ebp+0x10))  # => eax
15546     89/<- %edx 0/r32/eax
15547     3d/compare-eax-and 0/imm32/false
15548     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
15549     (will-not-write-some-register? %ecx *(ebp+0x14) *(ebp+0x18))  # => eax
15550     89/<- %edx 0/r32/eax
15551     # check emit-spill?
15552     3d/compare-eax-and 0/imm32/false
15553     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
15554     # TODO: assert(size-of(output) == 4)
15555     # *Curr-local-stack-offset -= 4
15556     81 5/subop/subtract *Curr-local-stack-offset 4/imm32
15557     # emit spill
15558     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
15559     (emit-push-register *(ebp+8) %eax)
15560 $push-output-and-maybe-emit-spill:push:
15561     8b/-> *(ebp+0xc) 1/r32/ecx
15562     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
15563     # push(vars, {sv->value, emit-spill?})
15564     (push *(ebp+0x10) *eax)  # Stmt-var-value
15565     (push *(ebp+0x10) *(eax+4))  # Stmt-var-value
15566     (push *(ebp+0x10) %edx)
15567 $push-output-and-maybe-emit-spill:end:
15568     # . restore registers
15569     5a/pop-to-edx
15570     59/pop-to-ecx
15571     58/pop-to-eax
15572     # . epilogue
15573     89/<- %esp 5/r32/ebp
15574     5d/pop-to-ebp
15575     c3/return
15576 
15577 $push-output-and-maybe-emit-spill:abort:
15578     # error("var '" var->name "' initialized from an instruction must live in a register\n")
15579     (write-buffered *(ebp+0x1c) "var '")
15580     (write-buffered *(ebp+0x1c) *eax)  # Var-name
15581     (write-buffered *(ebp+0x1c) "' initialized from an instruction must live in a register\n")
15582     (flush *(ebp+0x1c))
15583     (stop *(ebp+0x20) 1)
15584     # never gets here
15585 
15586 emit-subx-cleanup-and-unconditional-nonlocal-branch:  # out: (addr buffered-file), stmt: (addr stmt1), vars: (addr stack live-var)
15587     # . prologue
15588     55/push-ebp
15589     89/<- %ebp 4/r32/esp
15590     # . save registers
15591     50/push-eax
15592     51/push-ecx
15593     # ecx = stmt
15594     8b/-> *(ebp+0xc) 1/r32/ecx
15595     # var target/eax: (addr array byte) = curr-stmt->inouts->value->name
15596     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15597     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15598     (lookup *eax *(eax+4))  # Var-name Var-name => eax
15599     # clean up until target block
15600     (emit-cleanup-code-until-target *(ebp+8) *(ebp+0x10) %eax)
15601     # emit jump to target block
15602     (emit-indent *(ebp+8) *Curr-block-depth)
15603     (write-buffered *(ebp+8) "e9/jump ")
15604     (write-buffered *(ebp+8) %eax)
15605     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
15606     (string-starts-with? %eax "break")
15607     3d/compare-eax-and 0/imm32/false
15608     {
15609       74/jump-if-= break/disp8
15610       (write-buffered *(ebp+8) ":break/disp32\n")
15611     }
15612     3d/compare-eax-and 0/imm32/false  # just in case the function call modified flags
15613     {
15614       75/jump-if-!= break/disp8
15615       (write-buffered *(ebp+8) ":loop/disp32\n")
15616     }
15617 $emit-subx-cleanup-and-unconditional-nonlocal-branch:end:
15618     # . restore registers
15619     59/pop-to-ecx
15620     58/pop-to-eax
15621     # . epilogue
15622     89/<- %esp 5/r32/ebp
15623     5d/pop-to-ebp
15624     c3/return
15625 
15626 is-mu-branch?:  # stmt: (addr stmt1) -> result/eax: boolean
15627     # . prologue
15628     55/push-ebp
15629     89/<- %ebp 4/r32/esp
15630     # . save registers
15631     51/push-ecx
15632     # ecx = lookup(stmt->operation)
15633     8b/-> *(ebp+8) 1/r32/ecx
15634     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
15635     89/<- %ecx 0/r32/eax
15636     # if (stmt->operation starts with "loop") return true
15637     (string-starts-with? %ecx "loop")  # => eax
15638     3d/compare-eax-and 0/imm32/false
15639     75/jump-if-not-equal $is-mu-branch?:end/disp8
15640     # otherwise return (stmt->operation starts with "break")
15641     (string-starts-with? %ecx "break")  # => eax
15642 $is-mu-branch?:end:
15643     # . restore registers
15644     59/pop-to-ecx
15645     # . epilogue
15646     89/<- %esp 5/r32/ebp
15647     5d/pop-to-ebp
15648     c3/return
15649 
15650 emit-reverse-break:  # out: (addr buffered-file), stmt: (addr stmt1)
15651     # . prologue
15652     55/push-ebp
15653     89/<- %ebp 4/r32/esp
15654     # . save registers
15655     50/push-eax
15656     # eax = stmt
15657     8b/-> *(ebp+0xc) 0/r32/eax
15658     #
15659     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
15660     (get Reverse-branch %eax 0x10 "reverse-branch: ")  # => eax: (addr handle array byte)
15661     (emit-indent *(ebp+8) *Curr-block-depth)
15662     (lookup *eax *(eax+4))  # => eax
15663     (write-buffered *(ebp+8) %eax)
15664     (write-buffered *(ebp+8) " break/disp32\n")
15665 $emit-reverse-break:end:
15666     # . restore registers
15667     58/pop-to-eax
15668     # . epilogue
15669     89/<- %esp 5/r32/ebp
15670     5d/pop-to-ebp
15671     c3/return
15672 
15673 == data
15674 
15675 # Table from Mu branch instructions to the reverse SubX opcodes for them.
15676 Reverse-branch:  # (table (handle array byte) (handle array byte))
15677   # a table is a stream
15678   0x1c0/imm32/write
15679   0/imm32/read
15680   0x1c0/imm32/size
15681   # data
15682   0x11/imm32/alloc-id   _string-break-if-=/imm32                0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
15683   0x11/imm32/alloc-id   _string-loop-if-=/imm32                 0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
15684   0x11/imm32/alloc-id   _string-break-if-!=/imm32               0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
15685   0x11/imm32/alloc-id   _string-loop-if-!=/imm32                0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
15686   0x11/imm32/alloc-id   _string-break-if-</imm32                0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
15687   0x11/imm32/alloc-id   _string-loop-if-</imm32                 0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
15688   0x11/imm32/alloc-id   _string-break-if->/imm32                0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
15689   0x11/imm32/alloc-id   _string-loop-if->/imm32                 0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
15690   0x11/imm32/alloc-id   _string-break-if-<=/imm32               0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
15691   0x11/imm32/alloc-id   _string-loop-if-<=/imm32                0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
15692   0x11/imm32/alloc-id   _string-break-if->=/imm32               0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
15693   0x11/imm32/alloc-id   _string-loop-if->=/imm32                0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
15694   0x11/imm32/alloc-id   _string-break-if-addr</imm32            0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
15695   0x11/imm32/alloc-id   _string-loop-if-addr</imm32             0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
15696   0x11/imm32/alloc-id   _string-break-if-addr>/imm32            0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
15697   0x11/imm32/alloc-id   _string-loop-if-addr>/imm32             0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
15698   0x11/imm32/alloc-id   _string-break-if-addr<=/imm32           0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
15699   0x11/imm32/alloc-id   _string-loop-if-addr<=/imm32            0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
15700   0x11/imm32/alloc-id   _string-break-if-addr>=/imm32           0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
15701   0x11/imm32/alloc-id   _string-loop-if-addr>=/imm32            0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
15702   0x11/imm32/alloc-id   _string-break-if-float</imm32           0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
15703   0x11/imm32/alloc-id   _string-loop-if-float</imm32            0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
15704   0x11/imm32/alloc-id   _string-break-if-float>/imm32           0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
15705   0x11/imm32/alloc-id   _string-loop-if-float>/imm32            0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
15706   0x11/imm32/alloc-id   _string-break-if-float<=/imm32          0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
15707   0x11/imm32/alloc-id   _string-loop-if-float<=/imm32           0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
15708   0x11/imm32/alloc-id   _string-break-if-float>=/imm32          0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
15709   0x11/imm32/alloc-id   _string-loop-if-float>=/imm32           0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
15710 
15711 == code
15712 
15713 emit-unconditional-jump-to-depth:  # out: (addr buffered-file), vars: (addr stack live-var), depth: int, label-suffix: (addr array byte)
15714     # . prologue
15715     55/push-ebp
15716     89/<- %ebp 4/r32/esp
15717     # . save registers
15718     50/push-eax
15719     51/push-ecx
15720     52/push-edx
15721     53/push-ebx
15722     56/push-esi
15723     # ecx = vars
15724     8b/-> *(ebp+0xc) 1/r32/ecx
15725     # var eax: int = vars->top
15726     8b/-> *ecx 0/r32/eax
15727     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
15728     8d/copy-address *(ecx+eax-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
15729     # var min/ecx: (addr handle var) = vars->data
15730     8d/copy-address *(ecx+8) 1/r32/ecx
15731     # edx = depth
15732     8b/-> *(ebp+0x10) 2/r32/edx
15733     {
15734 $emit-unconditional-jump-to-depth:loop:
15735       # if (curr < min) break
15736       39/compare %esi 1/r32/ecx
15737       0f 82/jump-if-addr< break/disp32
15738       # var v/ebx: (addr var) = lookup(*curr)
15739       (lookup *esi *(esi+4))  # => eax
15740       89/<- %ebx 0/r32/eax
15741       # if (v->block-depth < until-block-depth) break
15742       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
15743       0f 8c/jump-if-< break/disp32
15744       {
15745 $emit-unconditional-jump-to-depth:check:
15746         # if v->block-depth != until-block-depth, continue
15747         39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
15748         0f 85/jump-if-!= break/disp32
15749 $emit-unconditional-jump-to-depth:depth-found:
15750         # if v is not a literal, continue
15751         (size-of %ebx)  # => eax
15752         3d/compare-eax-and 0/imm32
15753         0f 85/jump-if-!= break/disp32
15754 $emit-unconditional-jump-to-depth:label-found:
15755         # emit unconditional jump, then return
15756         (emit-indent *(ebp+8) *Curr-block-depth)
15757         (write-buffered *(ebp+8) "e9/jump ")
15758         (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
15759         (write-buffered *(ebp+8) %eax)
15760         (write-buffered *(ebp+8) ":")
15761         (write-buffered *(ebp+8) *(ebp+0x14))
15762         (write-buffered *(ebp+8) "/disp32\n")
15763         eb/jump $emit-unconditional-jump-to-depth:end/disp8
15764       }
15765       # curr -= 12
15766       81 5/subop/subtract %esi 0xc/imm32
15767       e9/jump loop/disp32
15768     }
15769     # TODO: error if no label at 'depth' was found
15770 $emit-unconditional-jump-to-depth:end:
15771     # . restore registers
15772     5e/pop-to-esi
15773     5b/pop-to-ebx
15774     5a/pop-to-edx
15775     59/pop-to-ecx
15776     58/pop-to-eax
15777     # . epilogue
15778     89/<- %esp 5/r32/ebp
15779     5d/pop-to-ebp
15780     c3/return
15781 
15782 # emit clean-up code for 'vars' until some block depth
15783 # doesn't actually modify 'vars' so we need traverse manually inside the stack
15784 emit-cleanup-code-until-depth:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-depth: int
15785     # . prologue
15786     55/push-ebp
15787     89/<- %ebp 4/r32/esp
15788     # . save registers
15789     50/push-eax
15790     51/push-ecx
15791     52/push-edx
15792     53/push-ebx
15793     56/push-esi
15794 #?     (write-buffered Stderr "--- cleanup\n")
15795 #?     (flush Stderr)
15796     # ecx = vars
15797     8b/-> *(ebp+0xc) 1/r32/ecx
15798     # var esi: int = vars->top
15799     8b/-> *ecx 6/r32/esi
15800     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
15801     8d/copy-address *(ecx+esi-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
15802     # var min/ecx: (addr handle var) = vars->data
15803     81 0/subop/add %ecx 8/imm32
15804     # edx = until-block-depth
15805     8b/-> *(ebp+0x10) 2/r32/edx
15806     {
15807 $emit-cleanup-code-until-depth:loop:
15808       # if (curr < min) break
15809       39/compare %esi 1/r32/ecx
15810       0f 82/jump-if-addr< break/disp32
15811       # var v/ebx: (addr var) = lookup(*curr)
15812       (lookup *esi *(esi+4))  # => eax
15813       89/<- %ebx 0/r32/eax
15814 #?       (lookup *ebx *(ebx+4))  # Var-name
15815 #?       (write-buffered Stderr "var ")
15816 #?       (write-buffered Stderr %eax)
15817 #?       (write-buffered Stderr Newline)
15818 #?       (flush Stderr)
15819       # if (v->block-depth < until-block-depth) break
15820       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
15821       0f 8c/jump-if-< break/disp32
15822       # if v is in a register
15823       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
15824       {
15825         0f 84/jump-if-= break/disp32
15826         {
15827 $emit-cleanup-code-until-depth:check-for-previous-spill:
15828           8b/-> *(esi+8) 0/r32/eax  # Live-var-register-spilled
15829           3d/compare-eax-and 0/imm32/false
15830           74/jump-if-= break/disp8
15831 $emit-cleanup-code-until-depth:reclaim-var-in-register:
15832           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
15833           (emit-pop-register *(ebp+8) %eax)
15834         }
15835         eb/jump $emit-cleanup-code-until-depth:continue/disp8
15836       }
15837       # otherwise v is on the stack
15838       {
15839         75/jump-if-!= break/disp8
15840 $emit-cleanup-code-until-depth:var-on-stack:
15841         (size-of %ebx)  # => eax
15842         # don't emit code for labels
15843         3d/compare-eax-and 0/imm32
15844         74/jump-if-= break/disp8
15845 $emit-cleanup-code-until-depth:reclaim-var-on-stack:
15846         (emit-indent *(ebp+8) *Curr-block-depth)
15847         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
15848         (write-int32-hex-buffered *(ebp+8) %eax)
15849         (write-buffered *(ebp+8) "/imm32\n")
15850       }
15851 $emit-cleanup-code-until-depth:continue:
15852       # curr -= 12
15853       81 5/subop/subtract %esi 0xc/imm32
15854       e9/jump loop/disp32
15855     }
15856 $emit-cleanup-code-until-depth:end:
15857     # . restore registers
15858     5e/pop-to-esi
15859     5b/pop-to-ebx
15860     5a/pop-to-edx
15861     59/pop-to-ecx
15862     58/pop-to-eax
15863     # . epilogue
15864     89/<- %esp 5/r32/ebp
15865     5d/pop-to-ebp
15866     c3/return
15867 
15868 emit-push-register:  # out: (addr buffered-file), reg: (addr array byte)
15869     # . prologue
15870     55/push-ebp
15871     89/<- %ebp 4/r32/esp
15872     # eax = reg
15873     8b/-> *(ebp+0xc) 0/r32/eax
15874     # var prefix/eax: byte = reg->data[0]
15875     8a/copy-byte *(eax+4) 0/r32/AL
15876     81 4/subop/and %eax 0xff/imm32
15877     # if (prefix == 'x') push xmm register
15878     {
15879       3d/compare-eax-and 0x78/imm32/x
15880       0f 85/jump-if-!= break/disp32
15881       # TODO validate register
15882       (emit-indent *(ebp+8) *Curr-block-depth)
15883       (write-buffered *(ebp+8) "81 5/subop/subtract %esp 4/imm32\n")
15884       (emit-indent *(ebp+8) *Curr-block-depth)
15885       (write-buffered *(ebp+8) "f3 0f 11/<- *esp ")
15886       # var prefix/eax: byte = reg->data[3]
15887       8b/-> *(ebp+0xc) 0/r32/eax
15888       8a/copy-byte *(eax+7) 0/r32/AL
15889       81 4/subop/and %eax 0xff/imm32
15890       (write-byte-buffered *(ebp+8) %eax)
15891       (write-buffered *(ebp+8) "/x32\n")
15892       e9/jump $emit-push-register:end/disp32
15893     }
15894     # otherwise push gp register
15895     (emit-indent *(ebp+8) *Curr-block-depth)
15896     (write-buffered *(ebp+8) "ff 6/subop/push %")
15897     (write-buffered *(ebp+8) *(ebp+0xc))
15898     (write-buffered *(ebp+8) Newline)
15899 $emit-push-register:end:
15900     # . epilogue
15901     89/<- %esp 5/r32/ebp
15902     5d/pop-to-ebp
15903     c3/return
15904 
15905 emit-pop-register:  # out: (addr buffered-file), reg: (addr array byte)
15906     # . prologue
15907     55/push-ebp
15908     89/<- %ebp 4/r32/esp
15909     # eax = reg
15910     8b/-> *(ebp+0xc) 0/r32/eax
15911     # var prefix/eax: byte = reg->data[0]
15912     8a/copy-byte *(eax+4) 0/r32/AL
15913     81 4/subop/and %eax 0xff/imm32
15914     # if (prefix == 'x') pop to xmm register
15915     {
15916       3d/compare-eax-and 0x78/imm32/x
15917       0f 85/jump-if-!= break/disp32
15918       # TODO validate register
15919       (emit-indent *(ebp+8) *Curr-block-depth)
15920       (write-buffered *(ebp+8) "f3 0f 10/-> *esp ")
15921       # var prefix/eax: byte = reg->data[3]
15922       8b/-> *(ebp+0xc) 0/r32/eax
15923       8a/copy-byte *(eax+7) 0/r32/AL
15924       81 4/subop/and %eax 0xff/imm32
15925       (write-byte-buffered *(ebp+8) %eax)
15926       (write-buffered *(ebp+8) "/x32\n")
15927       (emit-indent *(ebp+8) *Curr-block-depth)
15928       (write-buffered *(ebp+8) "81 0/subop/add %esp 4/imm32\n")
15929       e9/jump $emit-push-register:end/disp32
15930     }
15931     # otherwise pop to gp register
15932     (emit-indent *(ebp+8) *Curr-block-depth)
15933     (write-buffered *(ebp+8) "8f 0/subop/pop %")
15934     (write-buffered *(ebp+8) *(ebp+0xc))
15935     (write-buffered *(ebp+8) Newline)
15936 $emit-pop-register:end:
15937     # . epilogue
15938     89/<- %esp 5/r32/ebp
15939     5d/pop-to-ebp
15940     c3/return
15941 
15942 # emit clean-up code for 'vars' until a given label is encountered
15943 # doesn't actually modify 'vars' so we need traverse manually inside the stack
15944 emit-cleanup-code-until-target:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-label: (addr array byte)
15945     # . prologue
15946     55/push-ebp
15947     89/<- %ebp 4/r32/esp
15948     # . save registers
15949     50/push-eax
15950     51/push-ecx
15951     52/push-edx
15952     53/push-ebx
15953     # ecx = vars
15954     8b/-> *(ebp+0xc) 1/r32/ecx
15955     # var eax: int = vars->top
15956     8b/-> *ecx 0/r32/eax
15957     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
15958     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
15959     # var min/ecx: (addr handle var) = vars->data
15960     81 0/subop/add %ecx 8/imm32
15961     {
15962 $emit-cleanup-code-until-target:loop:
15963       # if (curr < min) break
15964       39/compare %edx 1/r32/ecx
15965       0f 82/jump-if-addr< break/disp32
15966       # var v/ebx: (handle var) = lookup(*curr)
15967       (lookup *edx *(edx+4))  # => eax
15968       89/<- %ebx 0/r32/eax
15969       # if (v->name == until-block-label) break
15970       (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
15971       (string-equal? %eax *(ebp+0x10))  # => eax
15972       3d/compare-eax-and 0/imm32/false
15973       0f 85/jump-if-!= break/disp32
15974       # if v is in a register
15975       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
15976       {
15977         0f 84/jump-if-= break/disp32
15978         {
15979 $emit-cleanup-code-until-target:check-for-previous-spill:
15980           8b/-> *(edx+8) 0/r32/eax  # Live-var-register-spilled
15981           3d/compare-eax-and 0/imm32/false
15982           74/jump-if-= break/disp8
15983 $emit-cleanup-code-until-target:reclaim-var-in-register:
15984           (emit-indent *(ebp+8) *Curr-block-depth)
15985           (write-buffered *(ebp+8) "8f 0/subop/pop %")
15986           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
15987           (write-buffered *(ebp+8) %eax)
15988           (write-buffered *(ebp+8) Newline)
15989         }
15990         eb/jump $emit-cleanup-code-until-target:continue/disp8
15991       }
15992       # otherwise v is on the stack
15993       {
15994         75/jump-if-!= break/disp8
15995 $emit-cleanup-code-until-target:reclaim-var-on-stack:
15996         (size-of %ebx)  # => eax
15997         # don't emit code for labels
15998         3d/compare-eax-and 0/imm32
15999         74/jump-if-= break/disp8
16000         #
16001         (emit-indent *(ebp+8) *Curr-block-depth)
16002         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
16003         (write-int32-hex-buffered *(ebp+8) %eax)
16004         (write-buffered *(ebp+8) "/imm32\n")
16005       }
16006 $emit-cleanup-code-until-target:continue:
16007       # curr -= 12
16008       81 5/subop/subtract %edx 0xc/imm32
16009       e9/jump loop/disp32
16010     }
16011 $emit-cleanup-code-until-target:end:
16012     # . restore registers
16013     5b/pop-to-ebx
16014     5a/pop-to-edx
16015     59/pop-to-ecx
16016     58/pop-to-eax
16017     # . epilogue
16018     89/<- %esp 5/r32/ebp
16019     5d/pop-to-ebp
16020     c3/return
16021 
16022 # update Curr-local-stack-offset assuming vars until some block depth are popped
16023 # doesn't actually modify 'vars', so we need traverse manually inside the stack
16024 clean-up-stack-offset-state:  # vars: (addr stack live-var), until-block-depth: int
16025     # . prologue
16026     55/push-ebp
16027     89/<- %ebp 4/r32/esp
16028     # . save registers
16029     50/push-eax
16030     51/push-ecx
16031     52/push-edx
16032     53/push-ebx
16033     56/push-esi
16034     # ecx = vars
16035     8b/-> *(ebp+8) 1/r32/ecx
16036     # var esi: int = vars->top
16037     8b/-> *ecx 6/r32/esi
16038     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
16039     8d/copy-address *(ecx+esi-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
16040     # var min/ecx: (addr handle var) = vars->data
16041     81 0/subop/add %ecx 8/imm32
16042     # edx = until-block-depth
16043     8b/-> *(ebp+0xc) 2/r32/edx
16044     {
16045 $clean-up-stack-offset-state:loop:
16046       # if (curr < min) break
16047       39/compare %esi 1/r32/ecx
16048       0f 82/jump-if-addr< break/disp32
16049       # var v/ebx: (addr var) = lookup(*curr)
16050       (lookup *esi *(esi+4))  # => eax
16051       89/<- %ebx 0/r32/eax
16052       # if (v->block-depth < until-block-depth) break
16053       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
16054       0f 8c/jump-if-< break/disp32
16055       # if v is in a register
16056       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
16057       {
16058         0f 84/jump-if-= break/disp32
16059         {
16060 $clean-up-stack-offset-state:check-for-previous-spill:
16061           8b/-> *(esi+8) 0/r32/eax  # Live-var-register-spilled
16062           3d/compare-eax-and 0/imm32/false
16063           74/jump-if-= break/disp8
16064 $clean-up-stack-offset-state:reclaim-var-in-register:
16065           81 0/subop/add *Curr-local-stack-offset 4/imm32
16066         }
16067         eb/jump $clean-up-stack-offset-state:continue/disp8
16068       }
16069       # otherwise v is on the stack
16070       {
16071         75/jump-if-!= break/disp8
16072 $clean-up-stack-offset-state:var-on-stack:
16073         (size-of %ebx)  # => eax
16074         01/add-to *Curr-local-stack-offset 0/r32/eax
16075       }
16076 $clean-up-stack-offset-state:continue:
16077       # curr -= 12
16078       81 5/subop/subtract %esi 0xc/imm32
16079       e9/jump loop/disp32
16080     }
16081 $clean-up-stack-offset-state:end:
16082     # . restore registers
16083     5e/pop-to-esi
16084     5b/pop-to-ebx
16085     5a/pop-to-edx
16086     59/pop-to-ecx
16087     58/pop-to-eax
16088     # . epilogue
16089     89/<- %esp 5/r32/ebp
16090     5d/pop-to-ebp
16091     c3/return
16092 
16093 # Return true if there isn't a variable in 'vars' with the same block-depth
16094 # and register as 'v'.
16095 # 'v' is guaranteed not to be within 'vars'.
16096 not-yet-spilled-this-block?:  # v: (addr var), vars: (addr stack live-var) -> result/eax: boolean
16097     # . prologue
16098     55/push-ebp
16099     89/<- %ebp 4/r32/esp
16100     # . save registers
16101     51/push-ecx
16102     52/push-edx
16103     53/push-ebx
16104     56/push-esi
16105     57/push-edi
16106     # ecx = vars
16107     8b/-> *(ebp+0xc) 1/r32/ecx
16108     # var eax: int = vars->top
16109     8b/-> *ecx 0/r32/eax
16110     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
16111     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
16112     # var min/ecx: (addr handle var) = vars->data
16113     8d/copy-address *(ecx+8) 1/r32/ecx
16114     # var depth/ebx: int = v->block-depth
16115     8b/-> *(ebp+8) 3/r32/ebx
16116     8b/-> *(ebx+0x10) 3/r32/ebx  # Var-block-depth
16117     # var needle/esi: (addr array byte) = v->register
16118     8b/-> *(ebp+8) 6/r32/esi
16119     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
16120     89/<- %esi 0/r32/eax
16121     {
16122 $not-yet-spilled-this-block?:loop:
16123       # if (curr < min) break
16124       39/compare %edx 1/r32/ecx
16125       0f 82/jump-if-addr< break/disp32
16126       # var cand/edi: (addr var) = lookup(*curr)
16127       (lookup *edx *(edx+4))  # => eax
16128       89/<- %edi 0/r32/eax
16129       # if (cand->block-depth < depth) break
16130       39/compare *(edi+0x10) 3/r32/ebx  # Var-block-depth
16131       0f 8c/jump-if-< break/disp32
16132       # var cand-reg/edi: (array array byte) = cand->reg
16133       (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
16134       89/<- %edi 0/r32/eax
16135       # if (cand-reg == null) continue
16136       {
16137 $not-yet-spilled-this-block?:check-reg:
16138         81 7/subop/compare %edi 0/imm32
16139         0f 84/jump-if-= break/disp32
16140         # if (cand-reg == needle) return true
16141         (string-equal? %esi %edi)  # => eax
16142         3d/compare-eax-and 0/imm32/false
16143         74/jump-if-= break/disp8
16144 $not-yet-spilled-this-block?:return-false:
16145         b8/copy-to-eax 0/imm32/false
16146         eb/jump $not-yet-spilled-this-block?:end/disp8
16147       }
16148 $not-yet-spilled-this-block?:continue:
16149       # curr -= 12
16150       81 5/subop/subtract %edx 0xc/imm32
16151       e9/jump loop/disp32
16152     }
16153 $not-yet-spilled-this-block?:return-true:
16154     # return true
16155     b8/copy-to-eax 1/imm32/true
16156 $not-yet-spilled-this-block?:end:
16157     # . restore registers
16158     5f/pop-to-edi
16159     5e/pop-to-esi
16160     5b/pop-to-ebx
16161     5a/pop-to-edx
16162     59/pop-to-ecx
16163     # . epilogue
16164     89/<- %esp 5/r32/ebp
16165     5d/pop-to-ebp
16166     c3/return
16167 
16168 # could the register of 'v' ever be written to by one of the vars in fn-outputs?
16169 will-not-write-some-register?:  # v: (addr var), stmts: (addr list stmt), fn: (addr function) -> result/eax: boolean
16170     # . prologue
16171     55/push-ebp
16172     89/<- %ebp 4/r32/esp
16173     # eax = v
16174     8b/-> *(ebp+8) 0/r32/eax
16175     # var reg/eax: (addr array byte) = lookup(v->register)
16176     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
16177     # var target/eax: (addr var) = find-register(fn-outputs, reg)
16178     (find-register *(ebp+0x10) %eax)  # => eax
16179     # if (target == 0) return true
16180     {
16181       3d/compare-eax-and 0/imm32
16182       75/jump-if-!= break/disp8
16183       b8/copy-to-eax 1/imm32/true
16184       eb/jump $will-not-write-some-register?:end/disp8
16185     }
16186     # return !assigns-in-stmts?(stmts, target)
16187     (assigns-in-stmts? *(ebp+0xc) %eax)  # => eax
16188     3d/compare-eax-and 0/imm32/false
16189     # assume: true = 1, so no need to mask with 0x000000ff
16190     0f 94/set-if-= %al
16191 $will-not-write-some-register?:end:
16192     # . epilogue
16193     89/<- %esp 5/r32/ebp
16194     5d/pop-to-ebp
16195     c3/return
16196 
16197 # return fn output with matching register
16198 # always returns false if 'reg' is null
16199 find-register:  # fn: (addr function), reg: (addr array byte) -> result/eax: (addr var)
16200     # . prologue
16201     55/push-ebp
16202     89/<- %ebp 4/r32/esp
16203     # . save registers
16204     51/push-ecx
16205     # var curr/ecx: (addr list var) = lookup(fn->outputs)
16206     8b/-> *(ebp+8) 1/r32/ecx
16207     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
16208     89/<- %ecx 0/r32/eax
16209     {
16210 $find-register:loop:
16211       # if (curr == 0) break
16212       81 7/subop/compare %ecx 0/imm32
16213       74/jump-if-= break/disp8
16214       # eax = curr->value->register
16215       (lookup *ecx *(ecx+4))  # List-value List-value => eax
16216       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
16217       # if (eax == reg) return curr->value
16218 $find-register:compare:
16219       (string-equal? *(ebp+0xc) %eax)  # => eax
16220       {
16221         3d/compare-eax-and 0/imm32/false
16222         74/jump-if-= break/disp8
16223 $find-register:found:
16224         (lookup *ecx *(ecx+4))  # List-value List-value => eax
16225         eb/jump $find-register:end/disp8
16226       }
16227       # curr = lookup(curr->next)
16228       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
16229       89/<- %ecx 0/r32/eax
16230       #
16231       eb/jump loop/disp8
16232     }
16233 $find-register:end:
16234     # . restore registers
16235     59/pop-to-ecx
16236     # . epilogue
16237     89/<- %esp 5/r32/ebp
16238     5d/pop-to-ebp
16239     c3/return
16240 
16241 assigns-in-stmts?:  # stmts: (addr list stmt), v: (addr var) -> result/eax: boolean
16242     # . prologue
16243     55/push-ebp
16244     89/<- %ebp 4/r32/esp
16245     # . save registers
16246     51/push-ecx
16247     # var curr/ecx: (addr list stmt) = stmts
16248     8b/-> *(ebp+8) 1/r32/ecx
16249     {
16250       # if (curr == 0) break
16251       81 7/subop/compare %ecx 0/imm32
16252       74/jump-if-= break/disp8
16253       # if assigns-in-stmt?(curr->value, v) return true
16254       (lookup *ecx *(ecx+4))  # List-value List-value => eax
16255       (assigns-in-stmt? %eax *(ebp+0xc))  # => eax
16256       3d/compare-eax-and 0/imm32/false
16257       75/jump-if-!= break/disp8
16258       # curr = lookup(curr->next)
16259       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
16260       89/<- %ecx 0/r32/eax
16261       #
16262       eb/jump loop/disp8
16263     }
16264 $assigns-in-stmts?:end:
16265     # . restore registers
16266     59/pop-to-ecx
16267     # . epilogue
16268     89/<- %esp 5/r32/ebp
16269     5d/pop-to-ebp
16270     c3/return
16271 
16272 assigns-in-stmt?:  # stmt: (addr stmt), v: (addr var) -> result/eax: boolean
16273     # . prologue
16274     55/push-ebp
16275     89/<- %ebp 4/r32/esp
16276     # . save registers
16277     51/push-ecx
16278     # ecx = stmt
16279     8b/-> *(ebp+8) 1/r32/ecx
16280     # if stmt is a stmt1, return assigns-in-stmt-vars?(stmt->outputs, v)
16281     {
16282       81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
16283       75/jump-if-!= break/disp8
16284       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
16285       (assigns-in-stmt-vars? %eax *(ebp+0xc))  # => eax
16286       eb/jump $assigns-in-stmt?:end/disp8
16287     }
16288     # if stmt is a block, return assigns-in-stmts?(stmt->stmts, v)
16289     {
16290       81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
16291       75/jump-if-!= break/disp8
16292       (lookup *(ecx+4) *(ecx+8))  # Block-stmts Block-stmts => eax
16293       (assigns-in-stmts? %eax *(ebp+0xc))  # => eax
16294       eb/jump $assigns-in-stmt?:end/disp8
16295     }
16296     # otherwise return false
16297     b8/copy 0/imm32/false
16298 $assigns-in-stmt?:end:
16299     # . restore registers
16300     59/pop-to-ecx
16301     # . epilogue
16302     89/<- %esp 5/r32/ebp
16303     5d/pop-to-ebp
16304     c3/return
16305 
16306 assigns-in-stmt-vars?:  # stmt-var: (addr stmt-var), v: (addr var) -> result/eax: boolean
16307     # . prologue
16308     55/push-ebp
16309     89/<- %ebp 4/r32/esp
16310     # . save registers
16311     51/push-ecx
16312     # var curr/ecx: (addr stmt-var) = stmt-var
16313     8b/-> *(ebp+8) 1/r32/ecx
16314     {
16315       # if (curr == 0) break
16316       81 7/subop/compare %ecx 0/imm32
16317       74/jump-if-= break/disp8
16318       # eax = lookup(curr->value)
16319       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
16320       # if (eax == v  &&  curr->is-deref? == false) return true
16321       {
16322         39/compare *(ebp+0xc) 0/r32/eax
16323         75/jump-if-!= break/disp8
16324         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
16325         75/jump-if-!= break/disp8
16326         b8/copy-to-eax 1/imm32/true
16327         eb/jump $assigns-in-stmt-vars?:end/disp8
16328       }
16329       # curr = lookup(curr->next)
16330       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
16331       89/<- %ecx 0/r32/eax
16332       #
16333       eb/jump loop/disp8
16334     }
16335 $assigns-in-stmt-vars?:end:
16336     # . restore registers
16337     59/pop-to-ecx
16338     # . epilogue
16339     89/<- %esp 5/r32/ebp
16340     5d/pop-to-ebp
16341     c3/return
16342 
16343 # is there a var before 'v' with the same block-depth and register on the 'vars' stack?
16344 # v is guaranteed to be within vars
16345 # 'start' is provided as an optimization, a pointer within vars
16346 # *start == v
16347 same-register-spilled-before?:  # v: (addr var), vars: (addr stack (handle var)), start: (addr var) -> result/eax: boolean
16348     # . prologue
16349     55/push-ebp
16350     89/<- %ebp 4/r32/esp
16351     # . save registers
16352     51/push-ecx
16353     52/push-edx
16354     53/push-ebx
16355     56/push-esi
16356     57/push-edi
16357     # ecx = v
16358     8b/-> *(ebp+8) 1/r32/ecx
16359     # var reg/edx: (addr array byte) = lookup(v->register)
16360     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
16361     89/<- %edx 0/r32/eax
16362     # var depth/ebx: int = v->block-depth
16363     8b/-> *(ecx+0x10) 3/r32/ebx  # Var-block-depth
16364     # var min/ecx: (addr handle var) = vars->data
16365     8b/-> *(ebp+0xc) 1/r32/ecx
16366     81 0/subop/add %ecx 8/imm32
16367     # TODO: check that start >= min and start < &vars->data[top]
16368     # TODO: check that *start == v
16369     # var curr/esi: (addr handle var) = start
16370     8b/-> *(ebp+0x10) 6/r32/esi
16371     # curr -= 8
16372     81 5/subop/subtract %esi 8/imm32
16373     {
16374 $same-register-spilled-before?:loop:
16375       # if (curr < min) break
16376       39/compare %esi 1/r32/ecx
16377       0f 82/jump-if-addr< break/disp32
16378       # var x/eax: (addr var) = lookup(*curr)
16379       (lookup *esi *(esi+4))  # => eax
16380       # if (x->block-depth < depth) break
16381       39/compare *(eax+0x10) 3/r32/ebx  # Var-block-depth
16382       0f 8c/jump-if-< break/disp32
16383       # if (x->register == 0) continue
16384       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
16385       74/jump-if-= $same-register-spilled-before?:continue/disp8
16386       # if (x->register == reg) return true
16387       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
16388       (string-equal? %eax %edx)  # => eax
16389       3d/compare-eax-and 0/imm32/false
16390       b8/copy-to-eax 1/imm32/true
16391       75/jump-if-!= $same-register-spilled-before?:end/disp8
16392 $same-register-spilled-before?:continue:
16393       # curr -= 8
16394       81 5/subop/subtract %esi 8/imm32
16395       e9/jump loop/disp32
16396     }
16397 $same-register-spilled-before?:false:
16398     b8/copy-to-eax 0/imm32/false
16399 $same-register-spilled-before?:end:
16400     # . restore registers
16401     5f/pop-to-edi
16402     5e/pop-to-esi
16403     5b/pop-to-ebx
16404     5a/pop-to-edx
16405     59/pop-to-ecx
16406     # . epilogue
16407     89/<- %esp 5/r32/ebp
16408     5d/pop-to-ebp
16409     c3/return
16410 
16411 # Clean up global state for 'vars' until some block depth (inclusive).
16412 #
16413 # This would be a simple series of pops, if it wasn't for fn outputs, which
16414 # can occur anywhere in the stack.
16415 # So we have to _compact_ the entire array underlying the stack.
16416 #
16417 # We want to allow a fn output register to be written to by locals before the
16418 # output is set.
16419 # So fn outputs can't just be pushed at the start of the function.
16420 #
16421 # We want to allow other locals to shadow a fn output register after the
16422 # output is set.
16423 # So the output can't just always override anything in the stack. Sequence matters.
16424 clean-up-blocks:  # vars: (addr stack live-var), until-block-depth: int, fn: (addr function)
16425     # pseudocode:
16426     #   to = vars->top  (which points outside the stack)
16427     #   while true
16428     #     if to <= 0
16429     #       break
16430     #     var v = vars->data[to-1]
16431     #     if v.depth < until and !in-function-outputs?(fn, v)
16432     #       break
16433     #     --to
16434     #   from = to
16435     #   while true
16436     #     if from >= vars->top
16437     #       break
16438     #     assert(from >= to)
16439     #     v = vars->data[from]
16440     #     if in-function-outputs?(fn, v)
16441     #       if from > to
16442     #         vars->data[to] = vars->data[from]
16443     #       ++to
16444     #     ++from
16445     #   vars->top = to
16446     #
16447     # . prologue
16448     55/push-ebp
16449     89/<- %ebp 4/r32/esp
16450     # . save registers
16451     50/push-eax
16452     52/push-edx
16453     53/push-ebx
16454     56/push-esi
16455     57/push-edi
16456     # ebx = vars
16457     8b/-> *(ebp+8) 3/r32/ebx
16458     # edx = until-block-depth
16459     8b/-> *(ebp+0xc) 2/r32/edx
16460 $clean-up-blocks:phase1:
16461     # var to/edi: int = vars->top
16462     8b/-> *ebx 7/r32/edi
16463     {
16464 $clean-up-blocks:loop1:
16465       # if (to <= 0) break
16466       81 7/subop/compare %edi 0/imm32
16467       7e/jump-if-<= break/disp8
16468       # var v/eax: (addr var) = lookup(vars->data[to-1]->var)
16469       8d/copy-address *(ebx+edi-4) 0/r32/eax  # vars + 8 + to - 12
16470       (lookup *eax *(eax+4))  # => eax
16471       # if (v->block-depth >= until-block-depth) continue
16472       39/compare *(eax+0x10) 2/r32/edx  # Var-block-depth
16473       {
16474         7d/jump-if->= break/disp8
16475         # if (!in-function-outputs?(fn, v)) break
16476         (in-function-outputs? *(ebp+0x10) %eax)  # => eax
16477         3d/compare-eax-and 0/imm32/false
16478         74/jump-if-= $clean-up-blocks:phase2/disp8
16479       }
16480 $clean-up-blocks:loop1-continue:
16481       # --to
16482       81 5/subop/subtract %edi 0xc/imm32
16483       #
16484       eb/jump loop/disp8
16485     }
16486 $clean-up-blocks:phase2:
16487     # var from/esi: int = to
16488     89/<- %esi 7/r32/edi
16489     {
16490 $clean-up-blocks:loop2:
16491       # if (from >= vars->top) break
16492       3b/compare 6/r32/esi *ebx
16493       7d/jump-if->= break/disp8
16494       # var v/eax: (addr var) = lookup(vars->data[from]->var)
16495       8d/copy-address *(ebx+esi+8) 0/r32/eax
16496       (lookup *eax *(eax+4))  # => eax
16497       # if !in-function-outputs?(fn, v) continue
16498       (in-function-outputs? *(ebp+0x10) %eax)  # => eax
16499       3d/compare-eax-and 0/imm32/false
16500       74/jump-if-= $clean-up-blocks:loop2-continue/disp8
16501       # invariant: from >= to
16502       # if (from > to) vars->data[to] = vars->data[from]
16503       {
16504         39/compare %esi 7/r32/edi
16505         7e/jump-if-<= break/disp8
16506         56/push-esi
16507         57/push-edi
16508         # . var from/esi: (addr byte) = &vars->data[from]
16509         8d/copy-address *(ebx+esi+8) 6/r32/esi
16510         # . var to/edi: (addr byte) = &vars->data[to]
16511         8d/copy-address *(ebx+edi+8) 7/r32/edi
16512         # .
16513         8b/-> *esi 0/r32/eax
16514         89/<- *edi 0/r32/eax
16515         8b/-> *(esi+4) 0/r32/eax
16516         89/<- *(edi+4) 0/r32/eax
16517         8b/-> *(esi+8) 0/r32/eax
16518         89/<- *(edi+8) 0/r32/eax
16519         5f/pop-to-edi
16520         5e/pop-to-esi
16521       }
16522       # ++to
16523       81 0/subop/add %edi 0xc/imm32
16524 $clean-up-blocks:loop2-continue:
16525       # ++from
16526       81 0/subop/add %esi 0xc/imm32
16527       #
16528       eb/jump loop/disp8
16529     }
16530     89/<- *ebx 7/r32/edi
16531 $clean-up-blocks:end:
16532     # . restore registers
16533     5f/pop-to-edi
16534     5e/pop-to-esi
16535     5b/pop-to-ebx
16536     5a/pop-to-edx
16537     58/pop-to-eax
16538     # . epilogue
16539     89/<- %esp 5/r32/ebp
16540     5d/pop-to-ebp
16541     c3/return
16542 
16543 in-function-outputs?:  # fn: (addr function), target: (addr var) -> result/eax: boolean
16544     # . prologue
16545     55/push-ebp
16546     89/<- %ebp 4/r32/esp
16547     # . save registers
16548     51/push-ecx
16549     # var curr/ecx: (addr list var) = lookup(fn->outputs)
16550     8b/-> *(ebp+8) 1/r32/ecx
16551     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
16552     89/<- %ecx 0/r32/eax
16553     # while curr != null
16554     {
16555       81 7/subop/compare %ecx 0/imm32
16556       74/jump-if-= break/disp8
16557       # var v/eax: (addr var) = lookup(curr->value)
16558       (lookup *ecx *(ecx+4))  # List-value List-value => eax
16559       # if (v == target) return true
16560       39/compare *(ebp+0xc) 0/r32/eax
16561       b8/copy-to-eax 1/imm32/true
16562       74/jump-if-= $in-function-outputs?:end/disp8
16563       # curr = curr->next
16564       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
16565       89/<- %ecx 0/r32/eax
16566       #
16567       eb/jump loop/disp8
16568     }
16569     b8/copy-to-eax 0/imm32
16570 $in-function-outputs?:end:
16571     # . restore registers
16572     59/pop-to-ecx
16573     # . epilogue
16574     89/<- %esp 5/r32/ebp
16575     5d/pop-to-ebp
16576     c3/return
16577 
16578 emit-subx-var-def:  # out: (addr buffered-file), stmt: (addr stmt)
16579     # . prologue
16580     55/push-ebp
16581     89/<- %ebp 4/r32/esp
16582     # . save registers
16583     50/push-eax
16584     51/push-ecx
16585     52/push-edx
16586     # eax = stmt
16587     8b/-> *(ebp+0xc) 0/r32/eax
16588     # var v/ecx: (addr var)
16589     (lookup *(eax+4) *(eax+8))  # Vardef-var Vardef-var => eax
16590     89/<- %ecx 0/r32/eax
16591     # v->block-depth = *Curr-block-depth
16592     8b/-> *Curr-block-depth 0/r32/eax
16593     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
16594     # var n/edx: int = size-of(stmt->var)
16595     (size-of %ecx)  # => eax
16596     89/<- %edx 0/r32/eax
16597     # *Curr-local-stack-offset -= n
16598     29/subtract-from *Curr-local-stack-offset 2/r32/edx
16599     # v->offset = *Curr-local-stack-offset
16600     8b/-> *Curr-local-stack-offset 0/r32/eax
16601     89/<- *(ecx+0x14) 0/r32/eax  # Var-offset
16602     # if v is an array, do something special to initialize it
16603     {
16604       (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
16605       (is-mu-array? %eax)  # => eax
16606       3d/compare-eax-and 0/imm32/false
16607       0f 84/jump-if-= break/disp32
16608       # var array-size-without-size/edx: int = n-4
16609       81 5/subop/subtract %edx 4/imm32
16610       #
16611       (emit-array-data-initialization *(ebp+8) %edx)
16612       e9/jump $emit-subx-var-def:end/disp32
16613     }
16614     # another special-case for initializing streams
16615     # a stream is an array with 2 extra pointers
16616     {
16617       (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
16618       (is-mu-stream? %eax)  # => eax
16619       3d/compare-eax-and 0/imm32/false
16620       0f 84/jump-if-= break/disp32
16621       # var array-size-without-size/edx: int = n-12
16622       81 5/subop/subtract %edx 0xc/imm32
16623       (emit-array-data-initialization *(ebp+8) %edx)
16624       # emit read and write pointers
16625       (emit-indent *(ebp+8) *Curr-block-depth)
16626       (write-buffered *(ebp+8) "68/push 0/imm32\n")
16627       (emit-indent *(ebp+8) *Curr-block-depth)
16628       (write-buffered *(ebp+8) "68/push 0/imm32\n")
16629       #
16630       eb/jump $emit-subx-var-def:end/disp8
16631     }
16632     # while n > 0
16633     {
16634       81 7/subop/compare %edx 0/imm32
16635       7e/jump-if-<= break/disp8
16636       (emit-indent *(ebp+8) *Curr-block-depth)
16637       (write-buffered *(ebp+8) "68/push 0/imm32\n")
16638       # n -= 4
16639       81 5/subop/subtract %edx 4/imm32
16640       #
16641       eb/jump loop/disp8
16642     }
16643 $emit-subx-var-def:end:
16644     # . restore registers
16645     5a/pop-to-edx
16646     59/pop-to-ecx
16647     58/pop-to-eax
16648     # . epilogue
16649     89/<- %esp 5/r32/ebp
16650     5d/pop-to-ebp
16651     c3/return
16652 
16653 emit-array-data-initialization:  # out: (addr buffered-file), n: int
16654     # . prologue
16655     55/push-ebp
16656     89/<- %ebp 4/r32/esp
16657     #
16658     (emit-indent *(ebp+8) *Curr-block-depth)
16659     (write-buffered *(ebp+8) "(push-n-zero-bytes ")
16660     (write-int32-hex-buffered *(ebp+8) *(ebp+0xc))
16661     (write-buffered *(ebp+8) ")\n")
16662     (emit-indent *(ebp+8) *Curr-block-depth)
16663     (write-buffered *(ebp+8) "68/push ")
16664     (write-int32-hex-buffered *(ebp+8) *(ebp+0xc))
16665     (write-buffered *(ebp+8) "/imm32\n")
16666 $emit-array-data-initialization:end:
16667     # . epilogue
16668     89/<- %esp 5/r32/ebp
16669     5d/pop-to-ebp
16670     c3/return
16671 
16672 emit-subx-stmt:  # out: (addr buffered-file), stmt: (addr stmt), primitives: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
16673     # . prologue
16674     55/push-ebp
16675     89/<- %ebp 4/r32/esp
16676     # . save registers
16677     50/push-eax
16678     51/push-ecx
16679     # - some special-case primitives that don't actually use the 'primitives' data structure
16680     # var op/ecx: (addr array byte) = lookup(stmt->operation)
16681     8b/-> *(ebp+0xc) 1/r32/ecx
16682     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
16683     89/<- %ecx 0/r32/eax
16684     # array size
16685     {
16686       # if (!string-equal?(stmt->operation, "length")) break
16687       (string-equal? %ecx "length")  # => eax
16688       3d/compare-eax-and 0/imm32
16689       0f 84/jump-if-= break/disp32
16690       (translate-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16691       e9/jump $emit-subx-stmt:end/disp32
16692     }
16693     # index into array
16694     {
16695       # if (!string-equal?(stmt->operation, "index")) break
16696       (string-equal? %ecx "index")  # => eax
16697       3d/compare-eax-and 0/imm32
16698       0f 84/jump-if-= break/disp32
16699       (translate-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16700       e9/jump $emit-subx-stmt:end/disp32
16701     }
16702     # compute-offset for index into array
16703     {
16704       # if (!string-equal?(stmt->operation, "compute-offset")) break
16705       (string-equal? %ecx "compute-offset")  # => eax
16706       3d/compare-eax-and 0/imm32
16707       0f 84/jump-if-= break/disp32
16708       (translate-mu-compute-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16709       e9/jump $emit-subx-stmt:end/disp32
16710     }
16711     # get field from record
16712     {
16713       # if (!string-equal?(stmt->operation, "get")) break
16714       (string-equal? %ecx "get")  # => eax
16715       3d/compare-eax-and 0/imm32
16716       0f 84/jump-if-= break/disp32
16717       (translate-mu-get-stmt *(ebp+8) *(ebp+0xc))
16718       e9/jump $emit-subx-stmt:end/disp32
16719     }
16720     # allocate scalar
16721     {
16722       # if (!string-equal?(stmt->operation, "allocate")) break
16723       (string-equal? %ecx "allocate")  # => eax
16724       3d/compare-eax-and 0/imm32
16725       0f 84/jump-if-= break/disp32
16726       (translate-mu-allocate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16727       e9/jump $emit-subx-stmt:end/disp32
16728     }
16729     # copy-object
16730     {
16731       # if (!string-equal?(stmt->operation, "copy-object")) break
16732       (string-equal? %ecx "copy-object")  # => eax
16733       3d/compare-eax-and 0/imm32
16734       0f 84/jump-if-= break/disp32
16735       (translate-mu-copy-object-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16736       e9/jump $emit-subx-stmt:end/disp32
16737     }
16738     # allocate array
16739     {
16740       # if (!string-equal?(stmt->operation, "populate")) break
16741       (string-equal? %ecx "populate")  # => eax
16742       3d/compare-eax-and 0/imm32
16743       0f 84/jump-if-= break/disp32
16744       (translate-mu-populate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16745       e9/jump $emit-subx-stmt:end/disp32
16746     }
16747     # allocate stream
16748     {
16749       # if (!string-equal?(stmt->operation, "populate-stream")) break
16750       (string-equal? %ecx "populate-stream")  # => eax
16751       3d/compare-eax-and 0/imm32
16752       0f 84/jump-if-= break/disp32
16753       (translate-mu-populate-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16754       e9/jump $emit-subx-stmt:end/disp32
16755     }
16756     # read from stream
16757     {
16758       # if (!string-equal?(stmt->operation, "read-from-stream")) break
16759       (string-equal? %ecx "read-from-stream")  # => eax
16760       3d/compare-eax-and 0/imm32
16761       0f 84/jump-if-= break/disp32
16762       (translate-mu-read-from-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16763       e9/jump $emit-subx-stmt:end/disp32
16764     }
16765     # write to stream
16766     {
16767       # if (!string-equal?(stmt->operation, "write-to-stream")) break
16768       (string-equal? %ecx "write-to-stream")  # => eax
16769       3d/compare-eax-and 0/imm32
16770       0f 84/jump-if-= break/disp32
16771       (translate-mu-write-to-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16772       e9/jump $emit-subx-stmt:end/disp32
16773     }
16774     # - if stmt matches a primitive, emit it
16775     {
16776 $emit-subx-stmt:check-for-primitive:
16777       # var curr/eax: (addr primitive)
16778       (find-matching-primitive *(ebp+0x10) *(ebp+0xc))  # primitives, stmt => eax
16779       3d/compare-eax-and 0/imm32
16780       74/jump-if-= break/disp8
16781 $emit-subx-stmt:primitive:
16782       (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax)  # out, stmt, curr
16783       e9/jump $emit-subx-stmt:end/disp32
16784     }
16785     # - otherwise emit a call
16786     # TODO: type-checking
16787 $emit-subx-stmt:call:
16788     (emit-call *(ebp+8) *(ebp+0xc))
16789 $emit-subx-stmt:end:
16790     # . restore registers
16791     59/pop-to-ecx
16792     58/pop-to-eax
16793     # . epilogue
16794     89/<- %esp 5/r32/ebp
16795     5d/pop-to-ebp
16796     c3/return
16797 
16798 translate-mu-length-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
16799     # . prologue
16800     55/push-ebp
16801     89/<- %ebp 4/r32/esp
16802     # . save registers
16803     50/push-eax
16804     51/push-ecx
16805     52/push-edx
16806     53/push-ebx
16807     56/push-esi
16808     # esi = stmt
16809     8b/-> *(ebp+0xc) 6/r32/esi
16810     # var base/ebx: (addr var) = stmt->inouts[0]->value
16811     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16812     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16813     89/<- %ebx 0/r32/eax
16814     # var elemsize/ecx: int = array-element-size(base)
16815     (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
16816     89/<- %ecx 0/r32/eax
16817     # var outreg/edx: (addr array byte) = stmt->outputs[0]->value->register
16818     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
16819     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16820     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
16821     89/<- %edx 0/r32/eax
16822     # if elemsize == 1
16823     {
16824       81 7/subop/compare %ecx 1/imm32
16825       75/jump-if-!= break/disp8
16826 $translate-mu-length-stmt:size-1:
16827       (emit-save-size-to *(ebp+8) %ebx %edx)
16828       e9/jump $translate-mu-length-stmt:end/disp32
16829     }
16830     # if elemsize is a power of 2 less than 256
16831     {
16832       (power-of-2? %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
16833       3d/compare-eax-and 0/imm32/false
16834       74/jump-if-= break/disp8
16835       81 7/subop/compare %ecx 0xff/imm32
16836       7f/jump-if-> break/disp8
16837 $translate-mu-length-stmt:size-power-of-2:
16838       (emit-save-size-to *(ebp+8) %ebx %edx)
16839       (emit-divide-by-shift-right *(ebp+8) %edx %ecx)
16840       e9/jump $translate-mu-length-stmt:end/disp32
16841     }
16842     # otherwise, the complex case
16843     # . emit register spills
16844     {
16845 $translate-mu-length-stmt:complex:
16846       (string-equal? %edx "eax")  # => eax
16847       3d/compare-eax-and 0/imm32/false
16848       75/break-if-!= break/disp8
16849       (emit-indent *(ebp+8) *Curr-block-depth)
16850       (write-buffered *(ebp+8) "50/push-eax\n")
16851     }
16852     {
16853       (string-equal? %edx "ecx")  # => eax
16854       3d/compare-eax-and 0/imm32/false
16855       75/break-if-!= break/disp8
16856       (emit-indent *(ebp+8) *Curr-block-depth)
16857       (write-buffered *(ebp+8) "51/push-ecx\n")
16858     }
16859     {
16860       (string-equal? %edx "edx")  # => eax
16861       3d/compare-eax-and 0/imm32/false
16862       75/break-if-!= break/disp8
16863       (emit-indent *(ebp+8) *Curr-block-depth)
16864       (write-buffered *(ebp+8) "52/push-edx\n")
16865     }
16866     # .
16867     (emit-save-size-to *(ebp+8) %ebx "eax")
16868     (emit-indent *(ebp+8) *Curr-block-depth)
16869     (write-buffered *(ebp+8) "31/xor %edx 2/r32/edx\n")
16870     (emit-indent *(ebp+8) *Curr-block-depth)
16871     (write-buffered *(ebp+8) "b9/copy-to-ecx ")
16872     (write-int32-hex-buffered *(ebp+8) %ecx)
16873     (write-buffered *(ebp+8) "/imm32\n")
16874     (emit-indent *(ebp+8) *Curr-block-depth)
16875     (write-buffered *(ebp+8) "f7 7/subop/idiv-eax-edx-by %ecx\n")
16876     {
16877       (string-equal? %edx "eax")  # => eax
16878       3d/compare-eax-and 0/imm32/false
16879       75/break-if-!= break/disp8
16880       (emit-indent *(ebp+8) *Curr-block-depth)
16881       (write-buffered *(ebp+8) "89/<- %")
16882       (write-buffered *(ebp+8) %edx)
16883       (write-buffered *(ebp+8) " 0/r32/eax\n")
16884     }
16885     # . emit register restores
16886     {
16887       (string-equal? %edx "edx")  # => eax
16888       3d/compare-eax-and 0/imm32/false
16889       75/break-if-!= break/disp8
16890       (emit-indent *(ebp+8) *Curr-block-depth)
16891       (write-buffered *(ebp+8) "5a/pop-to-edx\n")
16892     }
16893     {
16894       (string-equal? %edx "ecx")  # => eax
16895       3d/compare-eax-and 0/imm32/false
16896       75/break-if-!= break/disp8
16897       (emit-indent *(ebp+8) *Curr-block-depth)
16898       (write-buffered *(ebp+8) "59/pop-to-ecx\n")
16899     }
16900     {
16901       (string-equal? %edx "eax")  # => eax
16902       3d/compare-eax-and 0/imm32/false
16903       75/break-if-!= break/disp8
16904       (emit-indent *(ebp+8) *Curr-block-depth)
16905       (write-buffered *(ebp+8) "58/pop-to-eax\n")
16906     }
16907 $translate-mu-length-stmt:end:
16908     # . restore registers
16909     5e/pop-to-esi
16910     5b/pop-to-ebx
16911     5a/pop-to-edx
16912     59/pop-to-ecx
16913     58/pop-to-eax
16914     # . epilogue
16915     89/<- %esp 5/r32/ebp
16916     5d/pop-to-ebp
16917     c3/return
16918 
16919 array-element-size:  # arr: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
16920     # . prologue
16921     55/push-ebp
16922     89/<- %ebp 4/r32/esp
16923     #
16924     (array-element-type-id *(ebp+8) *(ebp+0xc) *(ebp+0x10))  # => eax
16925     (size-of-type-id-as-array-element %eax)  # => eax
16926 $array-element-size:end:
16927     # . epilogue
16928     89/<- %esp 5/r32/ebp
16929     5d/pop-to-ebp
16930     c3/return
16931 
16932 array-element-type-id:  # v: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: type-id
16933     # precondition: n is positive
16934     # . prologue
16935     55/push-ebp
16936     89/<- %ebp 4/r32/esp
16937     #
16938     8b/-> *(ebp+8) 0/r32/eax
16939     # var t/eax: (addr type-tree)
16940     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
16941     # if t == 0 abort
16942     3d/compare-eax-with 0/imm32
16943     0f 84/jump-if-== $array-element-type-id:error0/disp32
16944     # if t->is-atom? abort
16945     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
16946     0f 85/jump-if-!= $array-element-type-id:error1/disp32
16947     # if (t->left == addr) t = t->right
16948     {
16949       50/push-eax
16950       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
16951       (is-simple-mu-type? %eax 2)  # addr => eax
16952       3d/compare-eax-with 0/imm32/false
16953       58/pop-to-eax
16954       74/jump-if-= break/disp8
16955 $array-element-type-id:skip-addr:
16956       (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
16957     }
16958     # if t == 0 abort
16959     3d/compare-eax-with 0/imm32
16960     0f 84/jump-if-= $array-element-type-id:error2/disp32
16961     # if t->is-atom? abort
16962     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
16963     0f 85/jump-if-!= $array-element-type-id:error2/disp32
16964     # if t->left != array abort
16965     {
16966       50/push-eax
16967       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
16968       (is-simple-mu-type? %eax 3)  # array => eax
16969       3d/compare-eax-with 0/imm32/false
16970       58/pop-to-eax
16971 $array-element-type-id:no-array:
16972       0f 84/jump-if-= $array-element-type-id:error2/disp32
16973     }
16974 $array-element-type-id:skip-array:
16975     # t = t->right
16976     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
16977     # if t == 0 abort
16978     3d/compare-eax-with 0/imm32
16979     0f 84/jump-if-= $array-element-type-id:error2/disp32
16980     # if t->is-atom? abort
16981     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
16982     0f 85/jump-if-!= $array-element-type-id:error2/disp32
16983     # return t->left->value
16984     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
16985     8b/-> *(eax+4) 0/r32/eax  # Type-tree-value
16986 $array-element-type-id:end:
16987     # . epilogue
16988     89/<- %esp 5/r32/ebp
16989     5d/pop-to-ebp
16990     c3/return
16991 
16992 $array-element-type-id:error0:
16993     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
16994     50/push-eax
16995     8b/-> *(ebp+8) 0/r32/eax
16996     (lookup *eax *(eax+4))  # Var-name Var-name => eax
16997     (write-buffered *(ebp+0xc) %eax)
16998     58/pop-to-eax
16999     (write-buffered *(ebp+0xc) "' has no type\n")
17000     (flush *(ebp+0xc))
17001     (stop *(ebp+0x10) 1)
17002     # never gets here
17003 
17004 $array-element-type-id:error1:
17005     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
17006     50/push-eax
17007     8b/-> *(ebp+8) 0/r32/eax
17008     (lookup *eax *(eax+4))  # Var-name Var-name => eax
17009     (write-buffered *(ebp+0xc) %eax)
17010     58/pop-to-eax
17011     (write-buffered *(ebp+0xc) "' has atomic type ")
17012     (write-int32-hex-buffered *(ebp+0xc) *(eax+4))  # Type-tree-value
17013     (write-buffered *(ebp+0xc) Newline)
17014     (flush *(ebp+0xc))
17015     (stop *(ebp+0x10) 1)
17016     # never gets here
17017 
17018 $array-element-type-id:error2:
17019     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
17020     50/push-eax
17021     8b/-> *(ebp+8) 0/r32/eax
17022     (lookup *eax *(eax+4))  # Var-name Var-name => eax
17023     (write-buffered *(ebp+0xc) %eax)
17024     58/pop-to-eax
17025     (write-buffered *(ebp+0xc) "' has non-array type\n")
17026     (flush *(ebp+0xc))
17027     (stop *(ebp+0x10) 1)
17028     # never gets here
17029 
17030 size-of-type-id-as-array-element:  # t: type-id -> result/eax: int
17031     # . prologue
17032     55/push-ebp
17033     89/<- %ebp 4/r32/esp
17034     # eax = t
17035     8b/-> *(ebp+8) 0/r32/eax
17036     # if t is 'byte', size is 1
17037     3d/compare-eax-and 8/imm32/byte
17038     {
17039       75/jump-if-!= break/disp8
17040       b8/copy-to-eax 1/imm32
17041       eb/jump $size-of-type-id-as-array-element:end/disp8
17042     }
17043     # otherwise proceed as usual
17044     (size-of-type-id %eax)  # => eax
17045 $size-of-type-id-as-array-element:end:
17046     # . epilogue
17047     89/<- %esp 5/r32/ebp
17048     5d/pop-to-ebp
17049     c3/return
17050 
17051 emit-save-size-to:  # out: (addr buffered-file), base: (addr var), outreg: (addr array byte)
17052     # . prologue
17053     55/push-ebp
17054     89/<- %ebp 4/r32/esp
17055     # . save registers
17056     50/push-eax
17057     53/push-ebx
17058     # ebx = base
17059     8b/-> *(ebp+0xc) 3/r32/ebx
17060     (emit-indent *(ebp+8) *Curr-block-depth)
17061     (write-buffered *(ebp+8) "8b/-> *")
17062     # if base is an (addr array ...) in a register
17063     {
17064       81 7/subop/compare *(ebx+0x18)) 0/imm32  # Var-register
17065       74/jump-if-= break/disp8
17066 $emit-save-size-to:emit-base-from-register:
17067       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
17068       (write-buffered *(ebp+8) %eax)
17069       eb/jump $emit-save-size-to:emit-output/disp8
17070     }
17071     # otherwise if base is an (array ...) on the stack
17072     {
17073       81 7/subop/compare *(ebx+0x14)) 0/imm32  # Var-offset
17074       74/jump-if-= break/disp8
17075 $emit-save-size-to:emit-base-from-stack:
17076       (write-buffered *(ebp+8) "(ebp+")
17077       (write-int32-hex-buffered *(ebp+8) *(ebx+0x14))  # Var-offset
17078       (write-buffered *(ebp+8) ")")
17079     }
17080 $emit-save-size-to:emit-output:
17081     (write-buffered *(ebp+8) " ")
17082     (get Mu-registers *(ebp+0x10) 0xc "Mu-registers")  # => eax
17083     (write-int32-hex-buffered *(ebp+8) *eax)
17084     (write-buffered *(ebp+8) "/r32\n")
17085 $emit-save-size-to:end:
17086     # . restore registers
17087     5b/pop-to-ebx
17088     58/pop-to-eax
17089     # . epilogue
17090     89/<- %esp 5/r32/ebp
17091     5d/pop-to-ebp
17092     c3/return
17093 
17094 emit-divide-by-shift-right:  # out: (addr buffered-file), reg: (addr array byte), size: int
17095     # . prologue
17096     55/push-ebp
17097     89/<- %ebp 4/r32/esp
17098     # . save registers
17099     50/push-eax
17100     #
17101     (emit-indent *(ebp+8) *Curr-block-depth)
17102     (write-buffered *(ebp+8) "c1/shift 5/subop/>> %")
17103     (write-buffered *(ebp+8) *(ebp+0xc))
17104     (write-buffered *(ebp+8) Space)
17105     (num-shift-rights *(ebp+0x10))  # => eax
17106     (write-int32-hex-buffered *(ebp+8) %eax)
17107     (write-buffered *(ebp+8) "/imm8\n")
17108 $emit-divide-by-shift-right:end:
17109     # . restore registers
17110     58/pop-to-eax
17111     # . epilogue
17112     89/<- %esp 5/r32/ebp
17113     5d/pop-to-ebp
17114     c3/return
17115 
17116 translate-mu-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
17117     # . prologue
17118     55/push-ebp
17119     89/<- %ebp 4/r32/esp
17120     # . save registers
17121     51/push-ecx
17122     # ecx = stmt
17123     8b/-> *(ebp+0xc) 1/r32/ecx
17124     # var base/ecx: (addr var) = stmt->inouts[0]
17125     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17126     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17127     89/<- %ecx 0/r32/eax
17128     # if (var->register) do one thing
17129     {
17130       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
17131       74/jump-if-= break/disp8
17132       # TODO: ensure there's no dereference
17133       (translate-mu-index-stmt-with-array-in-register *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
17134       eb/jump $translate-mu-index-stmt:end/disp8
17135     }
17136     # if (var->offset) do a different thing
17137     {
17138       81 7/subop/compare *(ecx+0x14) 0/imm32  # Var-offset
17139       74/jump-if-= break/disp8
17140       # TODO: ensure there's no dereference
17141       (translate-mu-index-stmt-with-array-on-stack *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
17142       eb/jump $translate-mu-index-stmt:end/disp8
17143     }
17144 $translate-mu-index-stmt:end:
17145     # . restore registers
17146     59/pop-to-ecx
17147     # . epilogue
17148     89/<- %esp 5/r32/ebp
17149     5d/pop-to-ebp
17150     c3/return
17151 
17152 $translate-mu-index-stmt-with-array:error1:
17153     (write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input must either lie in a register or be a literal\n")
17154     (flush *(ebp+0x10))
17155     (stop *(ebp+0x14) 1)
17156     # never gets here
17157 
17158 $translate-mu-index-stmt-with-array:error2:
17159     (write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input when in a register must be an int or offset\n")
17160     (flush *(ebp+0x10))
17161     (stop *(ebp+0x14) 1)
17162     # never gets here
17163 
17164 translate-mu-index-stmt-with-array-in-register:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
17165     # . prologue
17166     55/push-ebp
17167     89/<- %ebp 4/r32/esp
17168     # . save registers
17169     50/push-eax
17170     51/push-ecx
17171     52/push-edx
17172     53/push-ebx
17173     #
17174     (emit-indent *(ebp+8) *Curr-block-depth)
17175     (write-buffered *(ebp+8) "8d/copy-address *(")
17176     # TODO: ensure inouts[0] is in a register and not dereferenced
17177 $translate-mu-index-stmt-with-array-in-register:emit-base:
17178     # ecx = stmt
17179     8b/-> *(ebp+0xc) 1/r32/ecx
17180     # var base/ebx: (addr var) = inouts[0]
17181     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17182     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17183     89/<- %ebx 0/r32/eax
17184     # print base->register " + "
17185     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
17186     (write-buffered *(ebp+8) %eax)
17187     (write-buffered *(ebp+8) " + ")
17188     # var index/edx: (addr var) = inouts[1]
17189     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17190     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
17191     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17192     89/<- %edx 0/r32/eax
17193     # if index->register
17194     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
17195     {
17196       0f 84/jump-if-= break/disp32
17197 $translate-mu-index-stmt-with-array-in-register:emit-register-index:
17198       # if index is an int
17199       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
17200       (is-simple-mu-type? %eax 1)  # int => eax
17201       3d/compare-eax-and 0/imm32/false
17202       {
17203         0f 84/jump-if-= break/disp32
17204 $translate-mu-index-stmt-with-array-in-register:emit-int-register-index:
17205         # print index->register "<<" log2(array-element-size(base)) " + 4) "
17206         # . index->register "<<"
17207         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
17208         (write-buffered *(ebp+8) %eax)
17209         (write-buffered *(ebp+8) "<<")
17210         # . log2(array-element-size(base->type))
17211         # TODO: ensure size is a power of 2
17212         (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
17213         (num-shift-rights %eax)  # => eax
17214         (write-int32-hex-buffered *(ebp+8) %eax)
17215         e9/jump $translate-mu-index-stmt-with-array-in-register:emit-register-index-done/disp32
17216       }
17217       # if index->type is any other atom, abort
17218       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
17219       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
17220       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
17221       # if index has type (offset ...)
17222       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
17223       (is-simple-mu-type? %eax 7)  # => eax
17224       3d/compare-eax-and 0/imm32/false
17225       {
17226         0f 84/jump-if-= break/disp32
17227         # print index->register
17228 $translate-mu-index-stmt-with-array-in-register:emit-offset-register-index:
17229         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
17230         (write-buffered *(ebp+8) %eax)
17231       }
17232 $translate-mu-index-stmt-with-array-in-register:emit-register-index-done:
17233       (write-buffered *(ebp+8) " + 4) ")
17234       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
17235     }
17236     # otherwise if index is a literal
17237     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
17238     (is-simple-mu-type? %eax 0)  # => eax
17239     3d/compare-eax-and 0/imm32/false
17240     {
17241       0f 84/jump-if-= break/disp32
17242 $translate-mu-index-stmt-with-array-in-register:emit-literal-index:
17243       # var index-value/edx: int = parse-hex-int(index->name)
17244       (lookup *edx *(edx+4))  # Var-name Var-name => eax
17245       (parse-hex-int %eax)  # => eax
17246       89/<- %edx 0/r32/eax
17247       # offset = idx-value * array-element-size(base->type)
17248       (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
17249       f7 4/subop/multiply-into-edx-eax %edx  # clobbers edx
17250       # offset += 4 for array size
17251       05/add-to-eax 4/imm32
17252       # TODO: check edx for overflow
17253       # print offset
17254       (write-int32-hex-buffered *(ebp+8) %eax)
17255       (write-buffered *(ebp+8) ") ")
17256       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
17257     }
17258     # otherwise abort
17259     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
17260 $translate-mu-index-stmt-with-array-in-register:emit-output:
17261     # outputs[0] "/r32"
17262     8b/-> *(ebp+0xc) 1/r32/ecx
17263     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
17264     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17265     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
17266     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
17267     (write-int32-hex-buffered *(ebp+8) *eax)
17268     (write-buffered *(ebp+8) "/r32\n")
17269 $translate-mu-index-stmt-with-array-in-register:end:
17270     # . restore registers
17271     5b/pop-to-ebx
17272     5a/pop-to-edx
17273     59/pop-to-ecx
17274     58/pop-to-eax
17275     # . epilogue
17276     89/<- %esp 5/r32/ebp
17277     5d/pop-to-ebp
17278     c3/return
17279 
17280 translate-mu-index-stmt-with-array-on-stack:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
17281     # . prologue
17282     55/push-ebp
17283     89/<- %ebp 4/r32/esp
17284     # . save registers
17285     50/push-eax
17286     51/push-ecx
17287     52/push-edx
17288     53/push-ebx
17289     #
17290     (emit-indent *(ebp+8) *Curr-block-depth)
17291     (write-buffered *(ebp+8) "8d/copy-address *(ebp + ")
17292     # var curr/edx: (addr stmt-var) = lookup(stmt->inouts)
17293     8b/-> *(ebp+0xc) 0/r32/eax
17294     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17295     89/<- %edx 0/r32/eax
17296     # var base/ecx: (addr var) = lookup(curr->value)
17297     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17298     89/<- %ecx 0/r32/eax
17299     # var curr2/eax: (addr stmt-var) = lookup(curr->next)
17300     (lookup *(edx+8) *(edx+0xc))  # Stmt-var-next Stmt-var-next => eax
17301     # var index/edx: (handle var) = curr2->value
17302     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17303     89/<- %edx 0/r32/eax
17304     # if index->register
17305     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
17306     {
17307       0f 84/jump-if-= break/disp32
17308 $translate-mu-index-stmt-with-array-on-stack:emit-register-index:
17309       # if index is an int
17310       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
17311       (is-simple-mu-type? %eax 1)  # int => eax
17312       3d/compare-eax-and 0/imm32/false
17313       {
17314         0f 84/jump-if-= break/disp32
17315 $translate-mu-index-stmt-with-array-on-stack:emit-int-register-index:
17316         # print index->register "<<" log2(array-element-size(base)) " + " base->offset+4
17317         # . inouts[1]->register "<<"
17318         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
17319         (write-buffered *(ebp+8) %eax)
17320         (write-buffered *(ebp+8) "<<")
17321         # . log2(array-element-size(base))
17322         # TODO: ensure size is a power of 2
17323         (array-element-size %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
17324         (num-shift-rights %eax)  # => eax
17325         (write-int32-hex-buffered *(ebp+8) %eax)
17326         #
17327         (write-buffered *(ebp+8) " + ")
17328         #
17329         8b/-> *(ecx+0x14) 0/r32/eax  # Var-offset
17330         05/add-to-eax 4/imm32  # for array length
17331         (write-int32-hex-buffered *(ebp+8) %eax)
17332         e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done/disp32
17333       }
17334       # if index->type is any other atom, abort
17335       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
17336       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
17337       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
17338       # if index has type (offset ...)
17339       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
17340       (is-simple-mu-type? %eax 7)  # => eax
17341       3d/compare-eax-and 0/imm32/false
17342       {
17343         0f 84/jump-if-= break/disp32
17344         # print index->register
17345 $translate-mu-index-stmt-with-array-on-stack:emit-offset-register-index:
17346         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
17347         (write-buffered *(ebp+8) %eax)
17348       }
17349 $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done:
17350       (write-buffered *(ebp+8) ") ")
17351       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
17352     }
17353     # otherwise if index is a literal
17354     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
17355     (is-simple-mu-type? %eax 0)  # => eax
17356     3d/compare-eax-and 0/imm32/false
17357     {
17358       0f 84/jump-if-= break/disp32
17359 $translate-mu-index-stmt-with-array-on-stack:emit-literal-index:
17360       # var idx-value/edx: int = parse-hex-int(index->name)
17361       (lookup *edx *(edx+4))  # Var-name Var-name => eax
17362       (parse-hex-int %eax)  # Var-name => eax
17363       89/<- %edx 0/r32/eax
17364       # offset = idx-value * array-element-size(base)
17365       (array-element-size %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
17366       f7 4/subop/multiply-into-edx-eax %edx  # clobbers edx
17367       # offset += base->offset
17368       03/add *(ecx+0x14) 0/r32/eax  # Var-offset
17369       # offset += 4 for array size
17370       05/add-to-eax 4/imm32
17371       # TODO: check edx for overflow
17372       # print offset
17373       (write-int32-hex-buffered *(ebp+8) %eax)
17374       (write-buffered *(ebp+8) ") ")
17375       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
17376     }
17377     # otherwise abort
17378     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
17379 $translate-mu-index-stmt-with-array-on-stack:emit-output:
17380     # outputs[0] "/r32"
17381     8b/-> *(ebp+0xc) 0/r32/eax
17382     (lookup *(eax+0x14) *(eax+0x18))  # Stmt1-outputs Stmt1-outputs => eax
17383     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17384     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
17385     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
17386     (write-int32-hex-buffered *(ebp+8) *eax)
17387     (write-buffered *(ebp+8) "/r32\n")
17388 $translate-mu-index-stmt-with-array-on-stack:end:
17389     # . restore registers
17390     5b/pop-to-ebx
17391     5a/pop-to-edx
17392     59/pop-to-ecx
17393     58/pop-to-eax
17394     # . epilogue
17395     89/<- %esp 5/r32/ebp
17396     5d/pop-to-ebp
17397     c3/return
17398 
17399 translate-mu-compute-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
17400     # . prologue
17401     55/push-ebp
17402     89/<- %ebp 4/r32/esp
17403     # . save registers
17404     50/push-eax
17405     51/push-ecx
17406     52/push-edx
17407     53/push-ebx
17408     #
17409     (emit-indent *(ebp+8) *Curr-block-depth)
17410     (write-buffered *(ebp+8) "69/multiply")
17411     # ecx = stmt
17412     8b/-> *(ebp+0xc) 1/r32/ecx
17413     # var first-inout/ebx: (addr stmt-var) = stmt->inouts[0]
17414     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17415     89/<- %ebx 0/r32/eax
17416 $translate-mu-compute-index-stmt:emit-index:
17417     (lookup *(ebx+8) *(ebx+0xc))  # Stmt-var-next Stmt-var-next => eax
17418     (emit-subx-var-as-rm32 *(ebp+8) %eax)
17419     (write-buffered *(ebp+8) Space)
17420 $translate-mu-compute-index-stmt:emit-elem-size:
17421     # var base/ebx: (addr var)
17422     (lookup *ebx *(ebx+4))  # Stmt-var-value Stmt-var-value => eax
17423     89/<- %ebx 0/r32/eax
17424     # print array-element-size(base)
17425     (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
17426     (write-int32-hex-buffered *(ebp+8) %eax)
17427     (write-buffered *(ebp+8) "/imm32 ")
17428 $translate-mu-compute-index-stmt:emit-output:
17429     # outputs[0] "/r32"
17430     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
17431     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17432     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
17433     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
17434     (write-int32-hex-buffered *(ebp+8) *eax)
17435     (write-buffered *(ebp+8) "/r32\n")
17436 $translate-mu-compute-index-stmt:end:
17437     # . restore registers
17438     5b/pop-to-ebx
17439     5a/pop-to-edx
17440     59/pop-to-ecx
17441     58/pop-to-eax
17442     # . epilogue
17443     89/<- %esp 5/r32/ebp
17444     5d/pop-to-ebp
17445     c3/return
17446 
17447 translate-mu-get-stmt:  # out: (addr buffered-file), stmt: (addr stmt)
17448     # . prologue
17449     55/push-ebp
17450     89/<- %ebp 4/r32/esp
17451     # . save registers
17452     50/push-eax
17453     51/push-ecx
17454     52/push-edx
17455     #
17456     (emit-indent *(ebp+8) *Curr-block-depth)
17457     (write-buffered *(ebp+8) "8d/copy-address ")
17458     # ecx = stmt
17459     8b/-> *(ebp+0xc) 1/r32/ecx
17460     # var offset/edx: int = get offset of stmt
17461     (mu-get-offset %ecx)  # => eax
17462     89/<- %edx 0/r32/eax
17463     # var base/eax: (addr var) = stmt->inouts->value
17464     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17465     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17466     # if base is in a register
17467     81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
17468     {
17469       0f 84/jump-if-= break/disp32
17470 $translate-mu-get-stmt:emit-register-input:
17471       # emit "*(" base->register " + " offset ") "
17472       (write-buffered *(ebp+8) "*(")
17473       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
17474       (write-buffered *(ebp+8) %eax)
17475       (write-buffered *(ebp+8) " + ")
17476       (write-int32-hex-buffered *(ebp+8) %edx)
17477       (write-buffered *(ebp+8) ") ")
17478       e9/jump $translate-mu-get-stmt:emit-output/disp32
17479     }
17480     # otherwise base is on the stack
17481     {
17482 $translate-mu-get-stmt:emit-stack-input:
17483       # emit "*(ebp + " inouts[0]->stack-offset + offset ") "
17484       (write-buffered *(ebp+8) "*(ebp+")
17485       03/add *(eax+0x14) 2/r32/edx  # Var-offset
17486       (write-int32-hex-buffered *(ebp+8) %edx)
17487       (write-buffered *(ebp+8) ") ")
17488       eb/jump $translate-mu-get-stmt:emit-output/disp8
17489     }
17490 $translate-mu-get-stmt:emit-output:
17491     # var output/eax: (addr var) = stmt->outputs->value
17492     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
17493     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17494     # emit offset->register "/r32"
17495     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
17496     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
17497     (write-int32-hex-buffered *(ebp+8) *eax)
17498     (write-buffered *(ebp+8) "/r32\n")
17499 $translate-mu-get-stmt:end:
17500     # . restore registers
17501     5a/pop-to-edx
17502     59/pop-to-ecx
17503     58/pop-to-eax
17504     # . epilogue
17505     89/<- %esp 5/r32/ebp
17506     5d/pop-to-ebp
17507     c3/return
17508 
17509 translate-mu-copy-object-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
17510     # . prologue
17511     55/push-ebp
17512     89/<- %ebp 4/r32/esp
17513     # . save registers
17514     50/push-eax
17515     #
17516     (emit-indent *(ebp+8) *Curr-block-depth)
17517     (write-buffered *(ebp+8) "(copy-bytes")
17518     # eax = stmt
17519     8b/-> *(ebp+0xc) 0/r32/eax
17520     # var first-inout/eax: (addr stmt-var) = stmt->inouts[0]
17521     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17522     (emit-subx-call-operand *(ebp+8) %eax)
17523     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
17524     (emit-subx-call-operand *(ebp+8) %eax)
17525     (write-buffered *(ebp+8) Space)
17526     (addr-payload-size %eax *(ebp+0x10) *(ebp+0x14))  # => eax
17527     (write-int32-hex-buffered *(ebp+8) %eax)
17528     (write-buffered *(ebp+8) ")\n")
17529 $translate-mu-copy-object-stmt:end:
17530     # . restore registers
17531     58/pop-to-eax
17532     # . epilogue
17533     89/<- %esp 5/r32/ebp
17534     5d/pop-to-ebp
17535     c3/return
17536 
17537 translate-mu-allocate-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
17538     # . prologue
17539     55/push-ebp
17540     89/<- %ebp 4/r32/esp
17541     # . save registers
17542     50/push-eax
17543     56/push-esi
17544     57/push-edi
17545     # esi = stmt
17546     8b/-> *(ebp+0xc) 6/r32/esi
17547     # var target/edi: (addr stmt-var) = stmt->inouts[0]
17548     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17549     89/<- %edi 0/r32/eax
17550     #
17551     (emit-indent *(ebp+8) *Curr-block-depth)
17552     (write-buffered *(ebp+8) "(allocate Heap ")
17553     (addr-handle-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
17554     (write-int32-hex-buffered *(ebp+8) %eax)
17555     (emit-subx-call-operand *(ebp+8) %edi)
17556     (write-buffered *(ebp+8) ")\n")
17557 $translate-mu-allocate-stmt:end:
17558     # . restore registers
17559     5f/pop-to-edi
17560     5e/pop-to-esi
17561     58/pop-to-eax
17562     # . epilogue
17563     89/<- %esp 5/r32/ebp
17564     5d/pop-to-ebp
17565     c3/return
17566 
17567 addr-handle-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
17568     # . prologue
17569     55/push-ebp
17570     89/<- %ebp 4/r32/esp
17571     # var t/eax: (addr type-tree) = s->value->type
17572     8b/-> *(ebp+8) 0/r32/eax
17573     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17574     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
17575     # TODO: check eax != 0
17576     # TODO: check !t->is-atom?
17577     # TODO: check t->left == addr
17578     # t = t->right
17579 $addr-handle-payload-size:skip-addr:
17580     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17581     # TODO: check eax != 0
17582     # TODO: check !t->is-atom?
17583     # TODO: check t->left == handle
17584     # t = t->right
17585 $addr-handle-payload-size:skip-handle:
17586     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17587     # TODO: check eax != 0
17588     # if !t->is-atom? t = t->left
17589     81 7/subop/compare *eax 0/imm32/false
17590     {
17591       75/jump-if-!= break/disp8
17592       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
17593     }
17594     # TODO: check t->is-atom?
17595     # return size(t->value)
17596     (size-of-type-id *(eax+4))  # Type-tree-value => eax
17597 $addr-handle-payload-size:end:
17598     # . epilogue
17599     89/<- %esp 5/r32/ebp
17600     5d/pop-to-ebp
17601     c3/return
17602 
17603 addr-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
17604     # . prologue
17605     55/push-ebp
17606     89/<- %ebp 4/r32/esp
17607     # var t/eax: (addr type-tree) = s->value->type
17608     8b/-> *(ebp+8) 0/r32/eax
17609     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17610     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
17611     # TODO: check eax != 0
17612     # TODO: check !t->is-atom?
17613     # TODO: check t->left == addr
17614     # t = t->right
17615 $addr-payload-size:skip-addr:
17616     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17617     # TODO: check eax != 0
17618     # if !t->is-atom? t = t->left
17619     81 7/subop/compare *eax 0/imm32/false
17620     {
17621       75/jump-if-!= break/disp8
17622       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
17623     }
17624     # TODO: check t->is-atom?
17625     # return size(t->value)
17626     (size-of-type-id *(eax+4))  # Type-tree-value => eax
17627 $addr-payload-size:end:
17628     # . epilogue
17629     89/<- %esp 5/r32/ebp
17630     5d/pop-to-ebp
17631     c3/return
17632 
17633 translate-mu-populate-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
17634     # . prologue
17635     55/push-ebp
17636     89/<- %ebp 4/r32/esp
17637     # . save registers
17638     50/push-eax
17639     51/push-ecx
17640     56/push-esi
17641     57/push-edi
17642     # esi = stmt
17643     8b/-> *(ebp+0xc) 6/r32/esi
17644     # var target/edi: (addr stmt-var) = stmt->inouts[0]
17645     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17646     89/<- %edi 0/r32/eax
17647     # var len/ecx: (addr stmt-var) = stmt->inouts[1]
17648     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
17649     89/<- %ecx 0/r32/eax
17650     #
17651     (emit-indent *(ebp+8) *Curr-block-depth)
17652     (write-buffered *(ebp+8) "(allocate-array2 Heap ")
17653     (addr-handle-array-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
17654     (write-int32-hex-buffered *(ebp+8) %eax)
17655     (emit-subx-call-operand *(ebp+8) %ecx)
17656     (emit-subx-call-operand *(ebp+8) %edi)
17657     (write-buffered *(ebp+8) ")\n")
17658 $translate-mu-populate-stmt:end:
17659     # . restore registers
17660     5f/pop-to-edi
17661     5e/pop-to-esi
17662     59/pop-to-ecx
17663     58/pop-to-eax
17664     # . epilogue
17665     89/<- %esp 5/r32/ebp
17666     5d/pop-to-ebp
17667     c3/return
17668 
17669 translate-mu-populate-stream-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
17670     # . prologue
17671     55/push-ebp
17672     89/<- %ebp 4/r32/esp
17673     # . save registers
17674     50/push-eax
17675     51/push-ecx
17676     56/push-esi
17677     57/push-edi
17678     # esi = stmt
17679     8b/-> *(ebp+0xc) 6/r32/esi
17680     # var target/edi: (addr stmt-var) = stmt->inouts[0]
17681     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17682     89/<- %edi 0/r32/eax
17683     # var len/ecx: (addr stmt-var) = stmt->inouts[1]
17684     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
17685     89/<- %ecx 0/r32/eax
17686     #
17687     (emit-indent *(ebp+8) *Curr-block-depth)
17688     (write-buffered *(ebp+8) "(new-stream Heap ")
17689     (addr-handle-stream-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
17690     (write-int32-hex-buffered *(ebp+8) %eax)
17691     (emit-subx-call-operand *(ebp+8) %ecx)
17692     (emit-subx-call-operand *(ebp+8) %edi)
17693     (write-buffered *(ebp+8) ")\n")
17694 $translate-mu-populate-stream-stmt:end:
17695     # . restore registers
17696     5f/pop-to-edi
17697     5e/pop-to-esi
17698     59/pop-to-ecx
17699     58/pop-to-eax
17700     # . epilogue
17701     89/<- %esp 5/r32/ebp
17702     5d/pop-to-ebp
17703     c3/return
17704 
17705 translate-mu-read-from-stream-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
17706     # . prologue
17707     55/push-ebp
17708     89/<- %ebp 4/r32/esp
17709     # . save registers
17710     50/push-eax
17711     51/push-ecx
17712     56/push-esi
17713     57/push-edi
17714     # esi = stmt
17715     8b/-> *(ebp+0xc) 6/r32/esi
17716     # var stream/ecx: (addr stmt-var) = stmt->inouts[0]
17717     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17718     89/<- %ecx 0/r32/eax
17719     # var target/edi: (addr stmt-var) = stmt->inouts[1]
17720     (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
17721     89/<- %edi 0/r32/eax
17722     #
17723     (emit-indent *(ebp+8) *Curr-block-depth)
17724     (write-buffered *(ebp+8) "(read-from-stream")
17725     (emit-subx-call-operand *(ebp+8) %ecx)
17726     (emit-subx-call-operand *(ebp+8) %edi)
17727     (write-buffered *(ebp+8) Space)
17728     (addr-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
17729     (write-int32-hex-buffered *(ebp+8) %eax)
17730     (write-buffered *(ebp+8) ")\n")
17731 $translate-mu-read-from-stream-stmt:end:
17732     # . restore registers
17733     5f/pop-to-edi
17734     5e/pop-to-esi
17735     59/pop-to-ecx
17736     58/pop-to-eax
17737     # . epilogue
17738     89/<- %esp 5/r32/ebp
17739     5d/pop-to-ebp
17740     c3/return
17741 
17742 translate-mu-write-to-stream-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
17743     # . prologue
17744     55/push-ebp
17745     89/<- %ebp 4/r32/esp
17746     # . save registers
17747     50/push-eax
17748     51/push-ecx
17749     56/push-esi
17750     57/push-edi
17751     # esi = stmt
17752     8b/-> *(ebp+0xc) 6/r32/esi
17753     # var stream/ecx: (addr stmt-var) = stmt->inouts[0]
17754     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17755     89/<- %ecx 0/r32/eax
17756     # var target/edi: (addr stmt-var) = stmt->inouts[1]
17757     (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
17758     89/<- %edi 0/r32/eax
17759     #
17760     (emit-indent *(ebp+8) *Curr-block-depth)
17761     (write-buffered *(ebp+8) "(write-to-stream")
17762     (emit-subx-call-operand *(ebp+8) %ecx)
17763     (flush *(ebp+8))
17764     (emit-subx-call-operand *(ebp+8) %edi)
17765     (flush *(ebp+8))
17766     (write-buffered *(ebp+8) Space)
17767     (flush *(ebp+8))
17768     (addr-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
17769     (write-int32-hex-buffered *(ebp+8) %eax)
17770     (write-buffered *(ebp+8) ")\n")
17771 $translate-mu-write-to-stream-stmt:end:
17772     # . restore registers
17773     5f/pop-to-edi
17774     5e/pop-to-esi
17775     59/pop-to-ecx
17776     58/pop-to-eax
17777     # . epilogue
17778     89/<- %esp 5/r32/ebp
17779     5d/pop-to-ebp
17780     c3/return
17781 
17782 addr-handle-array-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
17783     # . prologue
17784     55/push-ebp
17785     89/<- %ebp 4/r32/esp
17786     # var t/eax: (addr type-tree) = s->value->type
17787     8b/-> *(ebp+8) 0/r32/eax
17788     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17789     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
17790     # TODO: check eax != 0
17791     # TODO: check !t->is-atom?
17792     # TODO: check t->left == addr
17793     # t = t->right
17794 $addr-handle-array-payload-size:skip-addr:
17795     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17796     # TODO: check eax != 0
17797     # TODO: check !t->is-atom?
17798     # TODO: check t->left == handle
17799     # t = t->right
17800 $addr-handle-array-payload-size:skip-handle:
17801     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17802     # TODO: check eax != 0
17803     # TODO: check !t->is-atom?
17804     # TODO: check t->left == array
17805     # t = t->right
17806 $addr-handle-array-payload-size:skip-array:
17807     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17808     # TODO: check eax != 0
17809     # if !t->is-atom? t = t->left
17810     81 7/subop/compare *eax 0/imm32/false
17811     {
17812       75/jump-if-!= break/disp8
17813       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
17814     }
17815 $addr-handle-array-payload-size:compute-size:
17816     # TODO: check t->is-atom?
17817     # return size(t->value)
17818     (size-of-type-id-as-array-element *(eax+4))  # Type-tree-value => eax
17819 $addr-handle-array-payload-size:end:
17820     # . epilogue
17821     89/<- %esp 5/r32/ebp
17822     5d/pop-to-ebp
17823     c3/return
17824 
17825 addr-handle-stream-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
17826     # . prologue
17827     55/push-ebp
17828     89/<- %ebp 4/r32/esp
17829     # var t/eax: (addr type-tree) = s->value->type
17830     8b/-> *(ebp+8) 0/r32/eax
17831     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17832     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
17833     # TODO: check eax != 0
17834     # TODO: check !t->is-atom?
17835     # TODO: check t->left == addr
17836     # t = t->right
17837 $addr-handle-stream-payload-size:skip-addr:
17838     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17839     # TODO: check eax != 0
17840     # TODO: check !t->is-atom?
17841     # TODO: check t->left == handle
17842     # t = t->right
17843 $addr-handle-stream-payload-size:skip-handle:
17844     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17845     # TODO: check eax != 0
17846     # TODO: check !t->is-atom?
17847     # TODO: check t->left == stream
17848     # t = t->right
17849 $addr-handle-stream-payload-size:skip-stream:
17850     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17851     # TODO: check eax != 0
17852     # if !t->is-atom? t = t->left
17853     81 7/subop/compare *eax 0/imm32/false
17854     {
17855       75/jump-if-!= break/disp8
17856       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
17857     }
17858 $addr-handle-stream-payload-size:compute-size:
17859     # TODO: check t->is-atom?
17860     # return size(t->value)
17861     (size-of-type-id-as-array-element *(eax+4))  # Type-tree-value => eax
17862 $addr-handle-stream-payload-size:end:
17863     # . epilogue
17864     89/<- %esp 5/r32/ebp
17865     5d/pop-to-ebp
17866     c3/return
17867 
17868 power-of-2?:  # n: int, err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: boolean
17869     # precondition: n is positive
17870     # . prologue
17871     55/push-ebp
17872     89/<- %ebp 4/r32/esp
17873     # eax = n
17874     8b/-> *(ebp+8) 0/r32/eax
17875     # if (n < 0) abort
17876     3d/compare-eax-with 0/imm32
17877     0f 8c/jump-if-< $power-of-2?:abort/disp32
17878     # var tmp/eax: int = n-1
17879     48/decrement-eax
17880     # var tmp2/eax: int = n & tmp
17881     23/and-> *(ebp+8) 0/r32/eax
17882     # return (tmp2 == 0)
17883     3d/compare-eax-and 0/imm32
17884     0f 94/set-byte-if-= %al
17885     81 4/subop/and %eax 0xff/imm32
17886 $power-of-2?:end:
17887     # . epilogue
17888     89/<- %esp 5/r32/ebp
17889     5d/pop-to-ebp
17890     c3/return
17891 
17892 $power-of-2?:abort:
17893     (write-buffered *(ebp+0xc) "power-of-2?: negative number\n")
17894     (flush *(ebp+0xc))
17895     (stop *(ebp+0x10) 1)
17896     # never gets here
17897 
17898 num-shift-rights:  # n: int -> result/eax: int
17899     # precondition: n is a positive power of 2
17900     # . prologue
17901     55/push-ebp
17902     89/<- %ebp 4/r32/esp
17903     # . save registers
17904     51/push-ecx
17905     # var curr/ecx: int = n
17906     8b/-> *(ebp+8) 1/r32/ecx
17907     # result = 0
17908     b8/copy-to-eax 0/imm32
17909     {
17910       # if (curr <= 1) break
17911       81 7/subop/compare %ecx 1/imm32
17912       7e/jump-if-<= break/disp8
17913       40/increment-eax
17914       c1/shift 5/subop/arithmetic-right %ecx 1/imm8
17915       eb/jump loop/disp8
17916     }
17917 $num-shift-rights:end:
17918     # . restore registers
17919     59/pop-to-ecx
17920     # . epilogue
17921     89/<- %esp 5/r32/ebp
17922     5d/pop-to-ebp
17923     c3/return
17924 
17925 mu-get-offset:  # stmt: (addr stmt) -> result/eax: int
17926     # . prologue
17927     55/push-ebp
17928     89/<- %ebp 4/r32/esp
17929     # var second-inout/eax: (addr stmt-var) = stmt->inouts->next
17930     8b/-> *(ebp+8) 0/r32/eax
17931     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17932     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
17933     # var output-var/eax: (addr var) = second-inout->value
17934     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17935 #?     (write-buffered Stderr "mu-get-offset: ")
17936 #?     (write-int32-hex-buffered Stderr %eax)
17937 #?     (write-buffered Stderr " name: ")
17938 #?     50/push-eax
17939 #?     (lookup *eax *(eax+4))  # Var-name
17940 #?     (write-buffered Stderr %eax)
17941 #?     58/pop-to-eax
17942 #?     (write-buffered Stderr Newline)
17943 #?     (flush Stderr)
17944     # return output-var->stack-offset
17945     8b/-> *(eax+0x14) 0/r32/eax  # Var-offset
17946 #?     (write-buffered Stderr "=> ")
17947 #?     (write-int32-hex-buffered Stderr %eax)
17948 #?     (write-buffered Stderr Newline)
17949 #?     (flush Stderr)
17950 $emit-get-offset:end:
17951     # . epilogue
17952     89/<- %esp 5/r32/ebp
17953     5d/pop-to-ebp
17954     c3/return
17955 
17956 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)
17957     # . prologue
17958     55/push-ebp
17959     89/<- %ebp 4/r32/esp
17960     # . save registers
17961     50/push-eax
17962     51/push-ecx
17963     56/push-esi
17964     # esi = block
17965     8b/-> *(ebp+0xc) 6/r32/esi
17966     # block->var->block-depth = *Curr-block-depth
17967     (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
17968     8b/-> *Curr-block-depth 1/r32/ecx
17969     89/<- *(eax+0x10) 1/r32/ecx  # Var-block-depth
17970     # var stmts/eax: (addr list stmt) = lookup(block->statements)
17971     (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
17972     #
17973     {
17974 $emit-subx-block:check-empty:
17975       3d/compare-eax-and 0/imm32
17976       0f 84/jump-if-= break/disp32
17977       (emit-indent *(ebp+8) *Curr-block-depth)
17978       (write-buffered *(ebp+8) "{\n")
17979       # var v/ecx: (addr var) = lookup(block->var)
17980       (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
17981       89/<- %ecx 0/r32/eax
17982       #
17983       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
17984       (write-buffered *(ebp+8) %eax)
17985       (write-buffered *(ebp+8) ":loop:\n")
17986       ff 0/subop/increment *Curr-block-depth
17987       (push *(ebp+0x10) *(esi+0xc))  # Block-var
17988       (push *(ebp+0x10) *(esi+0x10))  # Block-var
17989       (push *(ebp+0x10) 0)  # false
17990       # emit block->statements
17991       (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
17992       (emit-subx-stmt-list *(ebp+8) %eax *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
17993       (pop *(ebp+0x10))  # => eax
17994       (pop *(ebp+0x10))  # => eax
17995       (pop *(ebp+0x10))  # => eax
17996       ff 1/subop/decrement *Curr-block-depth
17997       (emit-indent *(ebp+8) *Curr-block-depth)
17998       (write-buffered *(ebp+8) "}\n")
17999       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
18000       (write-buffered *(ebp+8) %eax)
18001       (write-buffered *(ebp+8) ":break:\n")
18002     }
18003 $emit-subx-block:end:
18004     # . restore registers
18005     5e/pop-to-esi
18006     59/pop-to-ecx
18007     58/pop-to-eax
18008     # . epilogue
18009     89/<- %esp 5/r32/ebp
18010     5d/pop-to-ebp
18011     c3/return
18012 
18013 # Primitives supported
18014 # See mu_instructions for a summary of this linked-list data structure.
18015 #
18016 # For each operation, put variants with hard-coded registers before flexible ones.
18017 #
18018 # Unfortunately, our restrictions on addresses require that various fields in
18019 # primitives be handles, which complicates these definitions.
18020 #   - we need to insert dummy fields all over the place for fake alloc-ids
18021 #   - we can't use our syntax sugar of quoted literals for string fields
18022 #
18023 # Fake alloc-ids are needed because our type definitions up top require
18024 # handles but it's clearer to statically allocate these long-lived objects.
18025 # Fake alloc-ids are perfectly safe, but they can't be reclaimed.
18026 #
18027 # Every 'object' below starts with a fake alloc-id. It may also contain other
18028 # fake alloc-ids for various handle fields.
18029 #
18030 # I think of objects starting with a fake alloc-id as having type 'payload'.
18031 # It's not really intended to be created dynamically; for that use `allocate`
18032 # as usual.
18033 #
18034 # Idea for a notation to simplify such definitions:
18035 #   _Primitive-increment-eax:  # (payload primitive)
18036 #     0x11/alloc-id:fake:payload
18037 #     0x11 @(0x11 "increment")  # name
18038 #     0 0                       # inouts
18039 #     0x11 @(0x11/payload
18040 #            0x11 @(0x11/payload  # List-value
18041 #                   0 0             # Var-name
18042 #                   0x11 @(0x11     # Var-type
18043 #                          1/is-atom
18044 #                          1/value 0/unused   # Type-tree-left
18045 #                          0 0                # Type-tree-right
18046 #                         )
18047 #                   1               # block-depth
18048 #                   0               # stack-offset
18049 #                   0x11 @(0x11 "eax")  # Var-register
18050 #                  )
18051 #            0 0)                 # List-next
18052 #     ...
18053 #     _Primitive-increment-ecx/imm32/next
18054 #   ...
18055 # Awfully complex and non-obvious. But also clearly signals there's something
18056 # to learn here, so may be worth trying.
18057 #
18058 # '@' is just an initial thought. Punctuation used so far in Mu: () * % # / "
18059 #
18060 # For now we'll continue to just use comments and manually ensure they stay up
18061 # to date.
18062 == data
18063 Primitives:  # (addr primitive)
18064 # - increment/decrement
18065 _Primitive-increment-eax:  # (addr primitive)
18066     # var/eax <- increment => 40/increment-eax
18067     0x11/imm32/alloc-id:fake
18068     _string-increment/imm32/name
18069     0/imm32/no-inouts
18070     0/imm32/no-inouts
18071     0x11/imm32/alloc-id:fake
18072     Single-int-var-in-eax/imm32/outputs
18073     0x11/imm32/alloc-id:fake
18074     _string_40_increment_eax/imm32/subx-name
18075     0/imm32/no-rm32
18076     0/imm32/no-r32
18077     0/imm32/no-imm32
18078     0/imm32/no-imm8
18079     0/imm32/no-disp32
18080     0/imm32/no-xm32
18081     0/imm32/no-x32
18082     0x11/imm32/alloc-id:fake
18083     _Primitive-increment-ecx/imm32/next
18084 _Primitive-increment-ecx:  # (payload primitive)
18085     0x11/imm32/alloc-id:fake:payload
18086     # var/ecx <- increment => 41/increment-ecx
18087     0x11/imm32/alloc-id:fake
18088     _string-increment/imm32/name
18089     0/imm32/no-inouts
18090     0/imm32/no-inouts
18091     0x11/imm32/alloc-id:fake
18092     Single-int-var-in-ecx/imm32/outputs
18093     0x11/imm32/alloc-id:fake
18094     _string_41_increment_ecx/imm32/subx-name
18095     0/imm32/no-rm32
18096     0/imm32/no-r32
18097     0/imm32/no-imm32
18098     0/imm32/no-imm8
18099     0/imm32/no-disp32
18100     0/imm32/no-xm32
18101     0/imm32/no-x32
18102     0x11/imm32/alloc-id:fake
18103     _Primitive-increment-edx/imm32/next
18104 _Primitive-increment-edx:  # (payload primitive)
18105     0x11/imm32/alloc-id:fake:payload
18106     # var/edx <- increment => 42/increment-edx
18107     0x11/imm32/alloc-id:fake
18108     _string-increment/imm32/name
18109     0/imm32/no-inouts
18110     0/imm32/no-inouts
18111     0x11/imm32/alloc-id:fake
18112     Single-int-var-in-edx/imm32/outputs
18113     0x11/imm32/alloc-id:fake
18114     _string_42_increment_edx/imm32/subx-name
18115     0/imm32/no-rm32
18116     0/imm32/no-r32
18117     0/imm32/no-imm32
18118     0/imm32/no-imm8
18119     0/imm32/no-disp32
18120     0/imm32/no-xm32
18121     0/imm32/no-x32
18122     0x11/imm32/alloc-id:fake
18123     _Primitive-increment-ebx/imm32/next
18124 _Primitive-increment-ebx:  # (payload primitive)
18125     0x11/imm32/alloc-id:fake:payload
18126     # var/ebx <- increment => 43/increment-ebx
18127     0x11/imm32/alloc-id:fake
18128     _string-increment/imm32/name
18129     0/imm32/no-inouts
18130     0/imm32/no-inouts
18131     0x11/imm32/alloc-id:fake
18132     Single-int-var-in-ebx/imm32/outputs
18133     0x11/imm32/alloc-id:fake
18134     _string_43_increment_ebx/imm32/subx-name
18135     0/imm32/no-rm32
18136     0/imm32/no-r32
18137     0/imm32/no-imm32
18138     0/imm32/no-imm8
18139     0/imm32/no-disp32
18140     0/imm32/no-xm32
18141     0/imm32/no-x32
18142     0x11/imm32/alloc-id:fake
18143     _Primitive-increment-esi/imm32/next
18144 _Primitive-increment-esi:  # (payload primitive)
18145     0x11/imm32/alloc-id:fake:payload
18146     # var/esi <- increment => 46/increment-esi
18147     0x11/imm32/alloc-id:fake
18148     _string-increment/imm32/name
18149     0/imm32/no-inouts
18150     0/imm32/no-inouts
18151     0x11/imm32/alloc-id:fake
18152     Single-int-var-in-esi/imm32/outputs
18153     0x11/imm32/alloc-id:fake
18154     _string_46_increment_esi/imm32/subx-name
18155     0/imm32/no-rm32
18156     0/imm32/no-r32
18157     0/imm32/no-imm32
18158     0/imm32/no-imm8
18159     0/imm32/no-disp32
18160     0/imm32/no-xm32
18161     0/imm32/no-x32
18162     0x11/imm32/alloc-id:fake
18163     _Primitive-increment-edi/imm32/next
18164 _Primitive-increment-edi:  # (payload primitive)
18165     0x11/imm32/alloc-id:fake:payload
18166     # var/edi <- increment => 47/increment-edi
18167     0x11/imm32/alloc-id:fake
18168     _string-increment/imm32/name
18169     0/imm32/no-inouts
18170     0/imm32/no-inouts
18171     0x11/imm32/alloc-id:fake
18172     Single-int-var-in-edi/imm32/outputs
18173     0x11/imm32/alloc-id:fake
18174     _string_47_increment_edi/imm32/subx-name
18175     0/imm32/no-rm32
18176     0/imm32/no-r32
18177     0/imm32/no-imm32
18178     0/imm32/no-imm8
18179     0/imm32/no-disp32
18180     0/imm32/no-xm32
18181     0/imm32/no-x32
18182     0x11/imm32/alloc-id:fake
18183     _Primitive-decrement-eax/imm32/next
18184 _Primitive-decrement-eax:  # (payload primitive)
18185     0x11/imm32/alloc-id:fake:payload
18186     # var/eax <- decrement => 48/decrement-eax
18187     0x11/imm32/alloc-id:fake
18188     _string-decrement/imm32/name
18189     0/imm32/no-inouts
18190     0/imm32/no-inouts
18191     0x11/imm32/alloc-id:fake
18192     Single-int-var-in-eax/imm32/outputs
18193     0x11/imm32/alloc-id:fake
18194     _string_48_decrement_eax/imm32/subx-name
18195     0/imm32/no-rm32
18196     0/imm32/no-r32
18197     0/imm32/no-imm32
18198     0/imm32/no-imm8
18199     0/imm32/no-disp32
18200     0/imm32/no-xm32
18201     0/imm32/no-x32
18202     0x11/imm32/alloc-id:fake
18203     _Primitive-decrement-ecx/imm32/next
18204 _Primitive-decrement-ecx:  # (payload primitive)
18205     0x11/imm32/alloc-id:fake:payload
18206     # var/ecx <- decrement => 49/decrement-ecx
18207     0x11/imm32/alloc-id:fake
18208     _string-decrement/imm32/name
18209     0/imm32/no-inouts
18210     0/imm32/no-inouts
18211     0x11/imm32/alloc-id:fake
18212     Single-int-var-in-ecx/imm32/outputs
18213     0x11/imm32/alloc-id:fake
18214     _string_49_decrement_ecx/imm32/subx-name
18215     0/imm32/no-rm32
18216     0/imm32/no-r32
18217     0/imm32/no-imm32
18218     0/imm32/no-imm8
18219     0/imm32/no-disp32
18220     0/imm32/no-xm32
18221     0/imm32/no-x32
18222     0x11/imm32/alloc-id:fake
18223     _Primitive-decrement-edx/imm32/next
18224 _Primitive-decrement-edx:  # (payload primitive)
18225     0x11/imm32/alloc-id:fake:payload
18226     # var/edx <- decrement => 4a/decrement-edx
18227     0x11/imm32/alloc-id:fake
18228     _string-decrement/imm32/name
18229     0/imm32/no-inouts
18230     0/imm32/no-inouts
18231     0x11/imm32/alloc-id:fake
18232     Single-int-var-in-edx/imm32/outputs
18233     0x11/imm32/alloc-id:fake
18234     _string_4a_decrement_edx/imm32/subx-name
18235     0/imm32/no-rm32
18236     0/imm32/no-r32
18237     0/imm32/no-imm32
18238     0/imm32/no-imm8
18239     0/imm32/no-disp32
18240     0/imm32/no-xm32
18241     0/imm32/no-x32
18242     0x11/imm32/alloc-id:fake
18243     _Primitive-decrement-ebx/imm32/next
18244 _Primitive-decrement-ebx:  # (payload primitive)
18245     0x11/imm32/alloc-id:fake:payload
18246     # var/ebx <- decrement => 4b/decrement-ebx
18247     0x11/imm32/alloc-id:fake
18248     _string-decrement/imm32/name
18249     0/imm32/no-inouts
18250     0/imm32/no-inouts
18251     0x11/imm32/alloc-id:fake
18252     Single-int-var-in-ebx/imm32/outputs
18253     0x11/imm32/alloc-id:fake
18254     _string_4b_decrement_ebx/imm32/subx-name
18255     0/imm32/no-rm32
18256     0/imm32/no-r32
18257     0/imm32/no-imm32
18258     0/imm32/no-imm8
18259     0/imm32/no-disp32
18260     0/imm32/no-xm32
18261     0/imm32/no-x32
18262     0x11/imm32/alloc-id:fake
18263     _Primitive-decrement-esi/imm32/next
18264 _Primitive-decrement-esi:  # (payload primitive)
18265     0x11/imm32/alloc-id:fake:payload
18266     # var/esi <- decrement => 4e/decrement-esi
18267     0x11/imm32/alloc-id:fake
18268     _string-decrement/imm32/name
18269     0/imm32/no-inouts
18270     0/imm32/no-inouts
18271     0x11/imm32/alloc-id:fake
18272     Single-int-var-in-esi/imm32/outputs
18273     0x11/imm32/alloc-id:fake
18274     _string_4e_decrement_esi/imm32/subx-name
18275     0/imm32/no-rm32
18276     0/imm32/no-r32
18277     0/imm32/no-imm32
18278     0/imm32/no-imm8
18279     0/imm32/no-disp32
18280     0/imm32/no-xm32
18281     0/imm32/no-x32
18282     0x11/imm32/alloc-id:fake
18283     _Primitive-decrement-edi/imm32/next
18284 _Primitive-decrement-edi:  # (payload primitive)
18285     0x11/imm32/alloc-id:fake:payload
18286     # var/edi <- decrement => 4f/decrement-edi
18287     0x11/imm32/alloc-id:fake
18288     _string-decrement/imm32/name
18289     0/imm32/no-inouts
18290     0/imm32/no-inouts
18291     0x11/imm32/alloc-id:fake
18292     Single-int-var-in-edi/imm32/outputs
18293     0x11/imm32/alloc-id:fake
18294     _string_4f_decrement_edi/imm32/subx-name
18295     0/imm32/no-rm32
18296     0/imm32/no-r32
18297     0/imm32/no-imm32
18298     0/imm32/no-imm8
18299     0/imm32/no-disp32
18300     0/imm32/no-xm32
18301     0/imm32/no-x32
18302     0x11/imm32/alloc-id:fake
18303     _Primitive-increment-mem/imm32/next
18304 _Primitive-increment-mem:  # (payload primitive)
18305     0x11/imm32/alloc-id:fake:payload
18306     # increment var => ff 0/subop/increment *(ebp+__)
18307     0x11/imm32/alloc-id:fake
18308     _string-increment/imm32/name
18309     0x11/imm32/alloc-id:fake
18310     Single-int-var-in-mem/imm32/inouts
18311     0/imm32/no-outputs
18312     0/imm32/no-outputs
18313     0x11/imm32/alloc-id:fake
18314     _string_ff_subop_increment/imm32/subx-name
18315     1/imm32/rm32-is-first-inout
18316     0/imm32/no-r32
18317     0/imm32/no-imm32
18318     0/imm32/no-imm8
18319     0/imm32/no-disp32
18320     0/imm32/no-xm32
18321     0/imm32/no-x32
18322     0x11/imm32/alloc-id:fake
18323     _Primitive-increment-reg/imm32/next
18324 _Primitive-increment-reg:  # (payload primitive)
18325     0x11/imm32/alloc-id:fake:payload
18326     # var/reg <- increment => ff 0/subop/increment %__
18327     0x11/imm32/alloc-id:fake
18328     _string-increment/imm32/name
18329     0/imm32/no-inouts
18330     0/imm32/no-inouts
18331     0x11/imm32/alloc-id:fake
18332     Single-int-var-in-some-register/imm32/outputs
18333     0x11/imm32/alloc-id:fake
18334     _string_ff_subop_increment/imm32/subx-name
18335     3/imm32/rm32-is-first-output
18336     0/imm32/no-r32
18337     0/imm32/no-imm32
18338     0/imm32/no-imm8
18339     0/imm32/no-disp32
18340     0/imm32/no-xm32
18341     0/imm32/no-x32
18342     0x11/imm32/alloc-id:fake
18343     _Primitive-decrement-mem/imm32/next
18344 _Primitive-decrement-mem:  # (payload primitive)
18345     0x11/imm32/alloc-id:fake:payload
18346     # decrement var => ff 1/subop/decrement *(ebp+__)
18347     0x11/imm32/alloc-id:fake
18348     _string-decrement/imm32/name
18349     0x11/imm32/alloc-id:fake
18350     Single-int-var-in-mem/imm32/inouts
18351     0/imm32/no-outputs
18352     0/imm32/no-outputs
18353     0x11/imm32/alloc-id:fake
18354     _string_ff_subop_decrement/imm32/subx-name
18355     1/imm32/rm32-is-first-inout
18356     0/imm32/no-r32
18357     0/imm32/no-imm32
18358     0/imm32/no-imm8
18359     0/imm32/no-disp32
18360     0/imm32/no-xm32
18361     0/imm32/no-x32
18362     0x11/imm32/alloc-id:fake
18363     _Primitive-decrement-reg/imm32/next
18364 _Primitive-decrement-reg:  # (payload primitive)
18365     0x11/imm32/alloc-id:fake:payload
18366     # var/reg <- decrement => ff 1/subop/decrement %__
18367     0x11/imm32/alloc-id:fake
18368     _string-decrement/imm32/name
18369     0/imm32/no-inouts
18370     0/imm32/no-inouts
18371     0x11/imm32/alloc-id:fake
18372     Single-int-var-in-some-register/imm32/outputs
18373     0x11/imm32/alloc-id:fake
18374     _string_ff_subop_decrement/imm32/subx-name
18375     3/imm32/rm32-is-first-output
18376     0/imm32/no-r32
18377     0/imm32/no-imm32
18378     0/imm32/no-imm8
18379     0/imm32/no-disp32
18380     0/imm32/no-xm32
18381     0/imm32/no-x32
18382     0x11/imm32/alloc-id:fake
18383     _Primitive-add-to-eax/imm32/next
18384 # - add
18385 _Primitive-add-to-eax:  # (payload primitive)
18386     0x11/imm32/alloc-id:fake:payload
18387     # var/eax <- add lit => 05/add-to-eax lit/imm32
18388     0x11/imm32/alloc-id:fake
18389     _string-add/imm32/name
18390     0x11/imm32/alloc-id:fake
18391     Single-lit-var/imm32/inouts
18392     0x11/imm32/alloc-id:fake
18393     Single-int-var-in-eax/imm32/outputs
18394     0x11/imm32/alloc-id:fake
18395     _string_05_add_to_eax/imm32/subx-name
18396     0/imm32/no-rm32
18397     0/imm32/no-r32
18398     1/imm32/imm32-is-first-inout
18399     0/imm32/no-imm8
18400     0/imm32/no-disp32
18401     0/imm32/no-xm32
18402     0/imm32/no-x32
18403     0x11/imm32/alloc-id:fake
18404     _Primitive-add-reg-to-reg/imm32/next
18405 _Primitive-add-reg-to-reg:  # (payload primitive)
18406     0x11/imm32/alloc-id:fake:payload
18407     # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32
18408     0x11/imm32/alloc-id:fake
18409     _string-add/imm32/name
18410     0x11/imm32/alloc-id:fake
18411     Single-int-var-in-some-register/imm32/inouts
18412     0x11/imm32/alloc-id:fake
18413     Single-int-var-in-some-register/imm32/outputs
18414     0x11/imm32/alloc-id:fake
18415     _string_01_add_to/imm32/subx-name
18416     3/imm32/rm32-is-first-output
18417     1/imm32/r32-is-first-inout
18418     0/imm32/no-imm32
18419     0/imm32/no-imm8
18420     0/imm32/no-disp32
18421     0/imm32/no-xm32
18422     0/imm32/no-x32
18423     0x11/imm32/alloc-id:fake
18424     _Primitive-add-reg-to-mem/imm32/next
18425 _Primitive-add-reg-to-mem:  # (payload primitive)
18426     0x11/imm32/alloc-id:fake:payload
18427     # add-to var1 var2/reg => 01/add-to var1 var2/r32
18428     0x11/imm32/alloc-id:fake
18429     _string-add-to/imm32/name
18430     0x11/imm32/alloc-id:fake
18431     Two-args-int-stack-int-reg/imm32/inouts
18432     0/imm32/no-outputs
18433     0/imm32/no-outputs
18434     0x11/imm32/alloc-id:fake
18435     _string_01_add_to/imm32/subx-name
18436     1/imm32/rm32-is-first-inout
18437     2/imm32/r32-is-second-inout
18438     0/imm32/no-imm32
18439     0/imm32/no-imm8
18440     0/imm32/no-disp32
18441     0/imm32/no-xm32
18442     0/imm32/no-x32
18443     0x11/imm32/alloc-id:fake
18444     _Primitive-add-mem-to-reg/imm32/next
18445 _Primitive-add-mem-to-reg:  # (payload primitive)
18446     0x11/imm32/alloc-id:fake:payload
18447     # var1/reg <- add var2 => 03/add var2/rm32 var1/r32
18448     0x11/imm32/alloc-id:fake
18449     _string-add/imm32/name
18450     0x11/imm32/alloc-id:fake
18451     Single-int-var-in-mem/imm32/inouts
18452     0x11/imm32/alloc-id:fake
18453     Single-int-var-in-some-register/imm32/outputs
18454     0x11/imm32/alloc-id:fake
18455     _string_03_add/imm32/subx-name
18456     1/imm32/rm32-is-first-inout
18457     3/imm32/r32-is-first-output
18458     0/imm32/no-imm32
18459     0/imm32/no-imm8
18460     0/imm32/no-disp32
18461     0/imm32/no-xm32
18462     0/imm32/no-x32
18463     0x11/imm32/alloc-id:fake
18464     _Primitive-add-lit-to-reg/imm32/next
18465 _Primitive-add-lit-to-reg:  # (payload primitive)
18466     0x11/imm32/alloc-id:fake:payload
18467     # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32
18468     0x11/imm32/alloc-id:fake
18469     _string-add/imm32/name
18470     0x11/imm32/alloc-id:fake
18471     Single-lit-var/imm32/inouts
18472     0x11/imm32/alloc-id:fake
18473     Single-int-var-in-some-register/imm32/outputs
18474     0x11/imm32/alloc-id:fake
18475     _string_81_subop_add/imm32/subx-name
18476     3/imm32/rm32-is-first-output
18477     0/imm32/no-r32
18478     1/imm32/imm32-is-first-inout
18479     0/imm32/no-imm8
18480     0/imm32/no-disp32
18481     0/imm32/no-xm32
18482     0/imm32/no-x32
18483     0x11/imm32/alloc-id:fake
18484     _Primitive-add-lit-to-mem/imm32/next
18485 _Primitive-add-lit-to-mem:  # (payload primitive)
18486     0x11/imm32/alloc-id:fake:payload
18487     # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32
18488     0x11/imm32/alloc-id:fake
18489     _string-add-to/imm32/name
18490     0x11/imm32/alloc-id:fake
18491     Int-var-and-literal/imm32/inouts
18492     0/imm32/no-outputs
18493     0/imm32/no-outputs
18494     0x11/imm32/alloc-id:fake
18495     _string_81_subop_add/imm32/subx-name
18496     1/imm32/rm32-is-first-inout
18497     0/imm32/no-r32
18498     2/imm32/imm32-is-second-inout
18499     0/imm32/no-imm8
18500     0/imm32/no-disp32
18501     0/imm32/no-xm32
18502     0/imm32/no-x32
18503     0x11/imm32/alloc-id:fake
18504     _Primitive-subtract-from-eax/imm32/next
18505 # - subtract
18506 _Primitive-subtract-from-eax:  # (payload primitive)
18507     0x11/imm32/alloc-id:fake:payload
18508     # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32
18509     0x11/imm32/alloc-id:fake
18510     _string-subtract/imm32/name
18511     0x11/imm32/alloc-id:fake
18512     Single-lit-var/imm32/inouts
18513     0x11/imm32/alloc-id:fake
18514     Single-int-var-in-eax/imm32/outputs
18515     0x11/imm32/alloc-id:fake
18516     _string_2d_subtract_from_eax/imm32/subx-name
18517     0/imm32/no-rm32
18518     0/imm32/no-r32
18519     1/imm32/imm32-is-first-inout
18520     0/imm32/no-imm8
18521     0/imm32/no-disp32
18522     0/imm32/no-xm32
18523     0/imm32/no-x32
18524     0x11/imm32/alloc-id:fake
18525     _Primitive-subtract-reg-from-reg/imm32/next
18526 _Primitive-subtract-reg-from-reg:  # (payload primitive)
18527     0x11/imm32/alloc-id:fake:payload
18528     # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32
18529     0x11/imm32/alloc-id:fake
18530     _string-subtract/imm32/name
18531     0x11/imm32/alloc-id:fake
18532     Single-int-var-in-some-register/imm32/inouts
18533     0x11/imm32/alloc-id:fake
18534     Single-int-var-in-some-register/imm32/outputs
18535     0x11/imm32/alloc-id:fake
18536     _string_29_subtract_from/imm32/subx-name
18537     3/imm32/rm32-is-first-output
18538     1/imm32/r32-is-first-inout
18539     0/imm32/no-imm32
18540     0/imm32/no-imm8
18541     0/imm32/no-disp32
18542     0/imm32/no-xm32
18543     0/imm32/no-x32
18544     0x11/imm32/alloc-id:fake
18545     _Primitive-subtract-reg-from-mem/imm32/next
18546 _Primitive-subtract-reg-from-mem:  # (payload primitive)
18547     0x11/imm32/alloc-id:fake:payload
18548     # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32
18549     0x11/imm32/alloc-id:fake
18550     _string-subtract-from/imm32/name
18551     0x11/imm32/alloc-id:fake
18552     Two-args-int-stack-int-reg/imm32/inouts
18553     0/imm32/no-outputs
18554     0/imm32/no-outputs
18555     0x11/imm32/alloc-id:fake
18556     _string_29_subtract_from/imm32/subx-name
18557     1/imm32/rm32-is-first-inout
18558     2/imm32/r32-is-second-inout
18559     0/imm32/no-imm32
18560     0/imm32/no-imm8
18561     0/imm32/no-disp32
18562     0/imm32/no-xm32
18563     0/imm32/no-x32
18564     0x11/imm32/alloc-id:fake
18565     _Primitive-subtract-mem-from-reg/imm32/next
18566 _Primitive-subtract-mem-from-reg:  # (payload primitive)
18567     0x11/imm32/alloc-id:fake:payload
18568     # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32
18569     0x11/imm32/alloc-id:fake
18570     _string-subtract/imm32/name
18571     0x11/imm32/alloc-id:fake
18572     Single-int-var-in-mem/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_2b_subtract/imm32/subx-name
18577     1/imm32/rm32-is-first-inout
18578     3/imm32/r32-is-first-output
18579     0/imm32/no-imm32
18580     0/imm32/no-imm8
18581     0/imm32/no-disp32
18582     0/imm32/no-xm32
18583     0/imm32/no-x32
18584     0x11/imm32/alloc-id:fake
18585     _Primitive-subtract-lit-from-reg/imm32/next
18586 _Primitive-subtract-lit-from-reg:  # (payload primitive)
18587     0x11/imm32/alloc-id:fake:payload
18588     # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32
18589     0x11/imm32/alloc-id:fake
18590     _string-subtract/imm32/name
18591     0x11/imm32/alloc-id:fake
18592     Single-lit-var/imm32/inouts
18593     0x11/imm32/alloc-id:fake
18594     Single-int-var-in-some-register/imm32/outputs
18595     0x11/imm32/alloc-id:fake
18596     _string_81_subop_subtract/imm32/subx-name
18597     3/imm32/rm32-is-first-output
18598     0/imm32/no-r32
18599     1/imm32/imm32-is-first-inout
18600     0/imm32/no-imm8
18601     0/imm32/no-disp32
18602     0/imm32/no-xm32
18603     0/imm32/no-x32
18604     0x11/imm32/alloc-id:fake
18605     _Primitive-subtract-lit-from-mem/imm32/next
18606 _Primitive-subtract-lit-from-mem:  # (payload primitive)
18607     0x11/imm32/alloc-id:fake:payload
18608     # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32
18609     0x11/imm32/alloc-id:fake
18610     _string-subtract-from/imm32/name
18611     0x11/imm32/alloc-id:fake
18612     Int-var-and-literal/imm32/inouts
18613     0/imm32/no-outputs
18614     0/imm32/no-outputs
18615     0x11/imm32/alloc-id:fake
18616     _string_81_subop_subtract/imm32/subx-name
18617     1/imm32/rm32-is-first-inout
18618     0/imm32/no-r32
18619     2/imm32/imm32-is-second-inout
18620     0/imm32/no-imm8
18621     0/imm32/no-disp32
18622     0/imm32/no-xm32
18623     0/imm32/no-x32
18624     0x11/imm32/alloc-id:fake
18625     _Primitive-and-with-eax/imm32/next
18626 # - and
18627 _Primitive-and-with-eax:  # (payload primitive)
18628     0x11/imm32/alloc-id:fake:payload
18629     # var/eax <- and lit => 25/and-with-eax lit/imm32
18630     0x11/imm32/alloc-id:fake
18631     _string-and/imm32/name
18632     0x11/imm32/alloc-id:fake
18633     Single-lit-var/imm32/inouts
18634     0x11/imm32/alloc-id:fake
18635     Single-int-var-in-eax/imm32/outputs
18636     0x11/imm32/alloc-id:fake
18637     _string_25_and_with_eax/imm32/subx-name
18638     0/imm32/no-rm32
18639     0/imm32/no-r32
18640     1/imm32/imm32-is-first-inout
18641     0/imm32/no-imm8
18642     0/imm32/no-disp32
18643     0/imm32/no-xm32
18644     0/imm32/no-x32
18645     0x11/imm32/alloc-id:fake
18646     _Primitive-and-reg-with-reg/imm32/next
18647 _Primitive-and-reg-with-reg:  # (payload primitive)
18648     0x11/imm32/alloc-id:fake:payload
18649     # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32
18650     0x11/imm32/alloc-id:fake
18651     _string-and/imm32/name
18652     0x11/imm32/alloc-id:fake
18653     Single-int-var-in-some-register/imm32/inouts
18654     0x11/imm32/alloc-id:fake
18655     Single-int-var-in-some-register/imm32/outputs
18656     0x11/imm32/alloc-id:fake
18657     _string_21_and_with/imm32/subx-name
18658     3/imm32/rm32-is-first-output
18659     1/imm32/r32-is-first-inout
18660     0/imm32/no-imm32
18661     0/imm32/no-imm8
18662     0/imm32/no-disp32
18663     0/imm32/no-xm32
18664     0/imm32/no-x32
18665     0x11/imm32/alloc-id:fake
18666     _Primitive-and-reg-with-mem/imm32/next
18667 _Primitive-and-reg-with-mem:  # (payload primitive)
18668     0x11/imm32/alloc-id:fake:payload
18669     # and-with var1 var2/reg => 21/and-with var1 var2/r32
18670     0x11/imm32/alloc-id:fake
18671     _string-and-with/imm32/name
18672     0x11/imm32/alloc-id:fake
18673     Two-args-int-stack-int-reg/imm32/inouts
18674     0/imm32/no-outputs
18675     0/imm32/no-outputs
18676     0x11/imm32/alloc-id:fake
18677     _string_21_and_with/imm32/subx-name
18678     1/imm32/rm32-is-first-inout
18679     2/imm32/r32-is-second-inout
18680     0/imm32/no-imm32
18681     0/imm32/no-imm8
18682     0/imm32/no-disp32
18683     0/imm32/no-xm32
18684     0/imm32/no-x32
18685     0x11/imm32/alloc-id:fake
18686     _Primitive-and-mem-with-reg/imm32/next
18687 _Primitive-and-mem-with-reg:  # (payload primitive)
18688     0x11/imm32/alloc-id:fake:payload
18689     # var1/reg <- and var2 => 23/and var2/rm32 var1/r32
18690     0x11/imm32/alloc-id:fake
18691     _string-and/imm32/name
18692     0x11/imm32/alloc-id:fake
18693     Single-int-var-in-mem/imm32/inouts
18694     0x11/imm32/alloc-id:fake
18695     Single-int-var-in-some-register/imm32/outputs
18696     0x11/imm32/alloc-id:fake
18697     _string_23_and/imm32/subx-name
18698     1/imm32/rm32-is-first-inout
18699     3/imm32/r32-is-first-output
18700     0/imm32/no-imm32
18701     0/imm32/no-imm8
18702     0/imm32/no-disp32
18703     0/imm32/no-xm32
18704     0/imm32/no-x32
18705     0x11/imm32/alloc-id:fake
18706     _Primitive-and-lit-with-reg/imm32/next
18707 _Primitive-and-lit-with-reg:  # (payload primitive)
18708     0x11/imm32/alloc-id:fake:payload
18709     # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32
18710     0x11/imm32/alloc-id:fake
18711     _string-and/imm32/name
18712     0x11/imm32/alloc-id:fake
18713     Single-lit-var/imm32/inouts
18714     0x11/imm32/alloc-id:fake
18715     Single-int-var-in-some-register/imm32/outputs
18716     0x11/imm32/alloc-id:fake
18717     _string_81_subop_and/imm32/subx-name
18718     3/imm32/rm32-is-first-output
18719     0/imm32/no-r32
18720     1/imm32/imm32-is-first-inout
18721     0/imm32/no-imm8
18722     0/imm32/no-disp32
18723     0/imm32/no-xm32
18724     0/imm32/no-x32
18725     0x11/imm32/alloc-id:fake
18726     _Primitive-and-lit-with-mem/imm32/next
18727 _Primitive-and-lit-with-mem:  # (payload primitive)
18728     0x11/imm32/alloc-id:fake:payload
18729     # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32
18730     0x11/imm32/alloc-id:fake
18731     _string-and-with/imm32/name
18732     0x11/imm32/alloc-id:fake
18733     Int-var-and-literal/imm32/inouts
18734     0/imm32/no-outputs
18735     0/imm32/no-outputs
18736     0x11/imm32/alloc-id:fake
18737     _string_81_subop_and/imm32/subx-name
18738     1/imm32/rm32-is-first-inout
18739     0/imm32/no-r32
18740     2/imm32/imm32-is-second-inout
18741     0/imm32/no-imm8
18742     0/imm32/no-disp32
18743     0/imm32/no-xm32
18744     0/imm32/no-x32
18745     0x11/imm32/alloc-id:fake
18746     _Primitive-or-with-eax/imm32/next
18747 # - or
18748 _Primitive-or-with-eax:  # (payload primitive)
18749     0x11/imm32/alloc-id:fake:payload
18750     # var/eax <- or lit => 0d/or-with-eax lit/imm32
18751     0x11/imm32/alloc-id:fake
18752     _string-or/imm32/name
18753     0x11/imm32/alloc-id:fake
18754     Single-lit-var/imm32/inouts
18755     0x11/imm32/alloc-id:fake
18756     Single-int-var-in-eax/imm32/outputs
18757     0x11/imm32/alloc-id:fake
18758     _string_0d_or_with_eax/imm32/subx-name
18759     0/imm32/no-rm32
18760     0/imm32/no-r32
18761     1/imm32/imm32-is-first-inout
18762     0/imm32/no-imm8
18763     0/imm32/no-disp32
18764     0/imm32/no-xm32
18765     0/imm32/no-x32
18766     0x11/imm32/alloc-id:fake
18767     _Primitive-or-reg-with-reg/imm32/next
18768 _Primitive-or-reg-with-reg:  # (payload primitive)
18769     0x11/imm32/alloc-id:fake:payload
18770     # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32
18771     0x11/imm32/alloc-id:fake
18772     _string-or/imm32/name
18773     0x11/imm32/alloc-id:fake
18774     Single-int-var-in-some-register/imm32/inouts
18775     0x11/imm32/alloc-id:fake
18776     Single-int-var-in-some-register/imm32/outputs
18777     0x11/imm32/alloc-id:fake
18778     _string_09_or_with/imm32/subx-name
18779     3/imm32/rm32-is-first-output
18780     1/imm32/r32-is-first-inout
18781     0/imm32/no-imm32
18782     0/imm32/no-imm8
18783     0/imm32/no-disp32
18784     0/imm32/no-xm32
18785     0/imm32/no-x32
18786     0x11/imm32/alloc-id:fake
18787     _Primitive-or-reg-with-mem/imm32/next
18788 _Primitive-or-reg-with-mem:  # (payload primitive)
18789     0x11/imm32/alloc-id:fake:payload
18790     # or-with var1 var2/reg => 09/or-with var1 var2/r32
18791     0x11/imm32/alloc-id:fake
18792     _string-or-with/imm32/name
18793     0x11/imm32/alloc-id:fake
18794     Two-args-int-stack-int-reg/imm32/inouts
18795     0/imm32/no-outputs
18796     0/imm32/no-outputs
18797     0x11/imm32/alloc-id:fake
18798     _string_09_or_with/imm32/subx-name
18799     1/imm32/rm32-is-first-inout
18800     2/imm32/r32-is-second-inout
18801     0/imm32/no-imm32
18802     0/imm32/no-imm8
18803     0/imm32/no-disp32
18804     0/imm32/no-xm32
18805     0/imm32/no-x32
18806     0x11/imm32/alloc-id:fake
18807     _Primitive-or-mem-with-reg/imm32/next
18808 _Primitive-or-mem-with-reg:  # (payload primitive)
18809     0x11/imm32/alloc-id:fake:payload
18810     # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32
18811     0x11/imm32/alloc-id:fake
18812     _string-or/imm32/name
18813     0x11/imm32/alloc-id:fake
18814     Single-int-var-in-mem/imm32/inouts
18815     0x11/imm32/alloc-id:fake
18816     Single-int-var-in-some-register/imm32/outputs
18817     0x11/imm32/alloc-id:fake
18818     _string_0b_or/imm32/subx-name
18819     1/imm32/rm32-is-first-inout
18820     3/imm32/r32-is-first-output
18821     0/imm32/no-imm32
18822     0/imm32/no-imm8
18823     0/imm32/no-disp32
18824     0/imm32/no-xm32
18825     0/imm32/no-x32
18826     0x11/imm32/alloc-id:fake
18827     _Primitive-or-lit-with-reg/imm32/next
18828 _Primitive-or-lit-with-reg:  # (payload primitive)
18829     0x11/imm32/alloc-id:fake:payload
18830     # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32
18831     0x11/imm32/alloc-id:fake
18832     _string-or/imm32/name
18833     0x11/imm32/alloc-id:fake
18834     Single-lit-var/imm32/inouts
18835     0x11/imm32/alloc-id:fake
18836     Single-int-var-in-some-register/imm32/outputs
18837     0x11/imm32/alloc-id:fake
18838     _string_81_subop_or/imm32/subx-name
18839     3/imm32/rm32-is-first-output
18840     0/imm32/no-r32
18841     1/imm32/imm32-is-first-inout
18842     0/imm32/no-imm8
18843     0/imm32/no-disp32
18844     0/imm32/no-xm32
18845     0/imm32/no-x32
18846     0x11/imm32/alloc-id:fake
18847     _Primitive-or-lit-with-mem/imm32/next
18848 _Primitive-or-lit-with-mem:  # (payload primitive)
18849     0x11/imm32/alloc-id:fake:payload
18850     # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32
18851     0x11/imm32/alloc-id:fake
18852     _string-or-with/imm32/name
18853     0x11/imm32/alloc-id:fake
18854     Int-var-and-literal/imm32/inouts
18855     0/imm32/no-outputs
18856     0/imm32/no-outputs
18857     0x11/imm32/alloc-id:fake
18858     _string_81_subop_or/imm32/subx-name
18859     1/imm32/rm32-is-first-inout
18860     0/imm32/no-r32
18861     2/imm32/imm32-is-second-inout
18862     0/imm32/no-imm8
18863     0/imm32/no-disp32
18864     0/imm32/no-xm32
18865     0/imm32/no-x32
18866     0x11/imm32/alloc-id:fake
18867     _Primitive-xor-with-eax/imm32/next
18868 # - xor
18869 _Primitive-xor-with-eax:  # (payload primitive)
18870     0x11/imm32/alloc-id:fake:payload
18871     # var/eax <- xor lit => 35/xor-with-eax lit/imm32
18872     0x11/imm32/alloc-id:fake
18873     _string-xor/imm32/name
18874     0x11/imm32/alloc-id:fake
18875     Single-lit-var/imm32/inouts
18876     0x11/imm32/alloc-id:fake
18877     Single-int-var-in-eax/imm32/outputs
18878     0x11/imm32/alloc-id:fake
18879     _string_35_xor_with_eax/imm32/subx-name
18880     0/imm32/no-rm32
18881     0/imm32/no-r32
18882     1/imm32/imm32-is-first-inout
18883     0/imm32/no-imm8
18884     0/imm32/no-disp32
18885     0/imm32/no-xm32
18886     0/imm32/no-x32
18887     0x11/imm32/alloc-id:fake
18888     _Primitive-xor-reg-with-reg/imm32/next
18889 _Primitive-xor-reg-with-reg:  # (payload primitive)
18890     0x11/imm32/alloc-id:fake:payload
18891     # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32
18892     0x11/imm32/alloc-id:fake
18893     _string-xor/imm32/name
18894     0x11/imm32/alloc-id:fake
18895     Single-int-var-in-some-register/imm32/inouts
18896     0x11/imm32/alloc-id:fake
18897     Single-int-var-in-some-register/imm32/outputs
18898     0x11/imm32/alloc-id:fake
18899     _string_31_xor_with/imm32/subx-name
18900     3/imm32/rm32-is-first-output
18901     1/imm32/r32-is-first-inout
18902     0/imm32/no-imm32
18903     0/imm32/no-imm8
18904     0/imm32/no-disp32
18905     0/imm32/no-xm32
18906     0/imm32/no-x32
18907     0x11/imm32/alloc-id:fake
18908     _Primitive-xor-reg-with-mem/imm32/next
18909 _Primitive-xor-reg-with-mem:  # (payload primitive)
18910     0x11/imm32/alloc-id:fake:payload
18911     # xor-with var1 var2/reg => 31/xor-with var1 var2/r32
18912     0x11/imm32/alloc-id:fake
18913     _string-xor-with/imm32/name
18914     0x11/imm32/alloc-id:fake
18915     Two-args-int-stack-int-reg/imm32/inouts
18916     0/imm32/no-outputs
18917     0/imm32/no-outputs
18918     0x11/imm32/alloc-id:fake
18919     _string_31_xor_with/imm32/subx-name
18920     1/imm32/rm32-is-first-inout
18921     2/imm32/r32-is-second-inout
18922     0/imm32/no-imm32
18923     0/imm32/no-imm8
18924     0/imm32/no-disp32
18925     0/imm32/no-xm32
18926     0/imm32/no-x32
18927     0x11/imm32/alloc-id:fake
18928     _Primitive-xor-mem-with-reg/imm32/next
18929 _Primitive-xor-mem-with-reg:  # (payload primitive)
18930     0x11/imm32/alloc-id:fake:payload
18931     # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32
18932     0x11/imm32/alloc-id:fake
18933     _string-xor/imm32/name
18934     0x11/imm32/alloc-id:fake
18935     Single-int-var-in-mem/imm32/inouts
18936     0x11/imm32/alloc-id:fake
18937     Single-int-var-in-some-register/imm32/outputs
18938     0x11/imm32/alloc-id:fake
18939     _string_33_xor/imm32/subx-name
18940     1/imm32/rm32-is-first-inout
18941     3/imm32/r32-is-first-output
18942     0/imm32/no-imm32
18943     0/imm32/no-imm8
18944     0/imm32/no-disp32
18945     0/imm32/no-xm32
18946     0/imm32/no-x32
18947     0x11/imm32/alloc-id:fake
18948     _Primitive-xor-lit-with-reg/imm32/next
18949 _Primitive-xor-lit-with-reg:  # (payload primitive)
18950     0x11/imm32/alloc-id:fake:payload
18951     # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32
18952     0x11/imm32/alloc-id:fake
18953     _string-xor/imm32/name
18954     0x11/imm32/alloc-id:fake
18955     Single-lit-var/imm32/inouts
18956     0x11/imm32/alloc-id:fake
18957     Single-int-var-in-some-register/imm32/outputs
18958     0x11/imm32/alloc-id:fake
18959     _string_81_subop_xor/imm32/subx-name
18960     3/imm32/rm32-is-first-output
18961     0/imm32/no-r32
18962     1/imm32/imm32-is-first-inout
18963     0/imm32/no-imm8
18964     0/imm32/no-disp32
18965     0/imm32/no-xm32
18966     0/imm32/no-x32
18967     0x11/imm32/alloc-id:fake
18968     _Primitive-xor-lit-with-mem/imm32/next
18969 _Primitive-xor-lit-with-mem:  # (payload primitive)
18970     0x11/imm32/alloc-id:fake:payload
18971     # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32
18972     0x11/imm32/alloc-id:fake
18973     _string-xor-with/imm32/name
18974     0x11/imm32/alloc-id:fake
18975     Int-var-and-literal/imm32/inouts
18976     0/imm32/no-outputs
18977     0/imm32/no-outputs
18978     0x11/imm32/alloc-id:fake
18979     _string_81_subop_xor/imm32/subx-name
18980     1/imm32/rm32-is-first-inout
18981     0/imm32/no-r32
18982     2/imm32/imm32-is-second-inout
18983     0/imm32/no-imm8
18984     0/imm32/no-disp32
18985     0/imm32/no-xm32
18986     0/imm32/no-x32
18987     0x11/imm32/alloc-id:fake
18988     _Primitive-shift-reg-left-by-lit/imm32/next
18989 _Primitive-shift-reg-left-by-lit:  # (payload primitive)
18990     0x11/imm32/alloc-id:fake:payload
18991     # var1/reg <- shift-left lit => c1/shift 4/subop/left var1/rm32 lit/imm32
18992     0x11/imm32/alloc-id:fake
18993     _string-shift-left/imm32/name
18994     0x11/imm32/alloc-id:fake
18995     Single-lit-var/imm32/inouts
18996     0x11/imm32/alloc-id:fake
18997     Single-int-var-in-some-register/imm32/outputs
18998     0x11/imm32/alloc-id:fake
18999     _string_c1_subop_shift_left/imm32/subx-name
19000     3/imm32/rm32-is-first-output
19001     0/imm32/no-r32
19002     0/imm32/no-imm32
19003     1/imm32/imm8-is-first-inout
19004     0/imm32/no-disp32
19005     0/imm32/no-xm32
19006     0/imm32/no-x32
19007     0x11/imm32/alloc-id:fake
19008     _Primitive-shift-reg-right-by-lit/imm32/next
19009 _Primitive-shift-reg-right-by-lit:  # (payload primitive)
19010     0x11/imm32/alloc-id:fake:payload
19011     # var1/reg <- shift-right lit => c1/shift 5/subop/right var1/rm32 lit/imm32
19012     0x11/imm32/alloc-id:fake
19013     _string-shift-right/imm32/name
19014     0x11/imm32/alloc-id:fake
19015     Single-lit-var/imm32/inouts
19016     0x11/imm32/alloc-id:fake
19017     Single-int-var-in-some-register/imm32/outputs
19018     0x11/imm32/alloc-id:fake
19019     _string_c1_subop_shift_right_padding_zeroes/imm32/subx-name
19020     3/imm32/rm32-is-first-output
19021     0/imm32/no-r32
19022     0/imm32/no-imm32
19023     1/imm32/imm8-is-first-inout
19024     0/imm32/no-disp32
19025     0/imm32/no-xm32
19026     0/imm32/no-x32
19027     0x11/imm32/alloc-id:fake
19028     _Primitive-shift-reg-right-signed-by-lit/imm32/next
19029 _Primitive-shift-reg-right-signed-by-lit:  # (payload primitive)
19030     0x11/imm32/alloc-id:fake:payload
19031     # var1/reg <- shift-right-signed lit => c1/shift 7/subop/right-preserving-sign var1/rm32 lit/imm32
19032     0x11/imm32/alloc-id:fake
19033     _string-shift-right-signed/imm32/name
19034     0x11/imm32/alloc-id:fake
19035     Single-lit-var/imm32/inouts
19036     0x11/imm32/alloc-id:fake
19037     Single-int-var-in-some-register/imm32/outputs
19038     0x11/imm32/alloc-id:fake
19039     _string_c1_subop_shift_right_preserving_sign/imm32/subx-name
19040     3/imm32/rm32-is-first-output
19041     0/imm32/no-r32
19042     0/imm32/no-imm32
19043     1/imm32/imm8-is-first-inout
19044     0/imm32/no-disp32
19045     0/imm32/no-xm32
19046     0/imm32/no-x32
19047     0x11/imm32/alloc-id:fake
19048     _Primitive-shift-mem-left-by-lit/imm32/next
19049 _Primitive-shift-mem-left-by-lit:  # (payload primitive)
19050     0x11/imm32/alloc-id:fake:payload
19051     # shift-left var1, lit => c1/shift 4/subop/left var1/rm32 lit/imm32
19052     0x11/imm32/alloc-id:fake
19053     _string-shift-left/imm32/name
19054     0x11/imm32/alloc-id:fake
19055     Int-var-and-literal/imm32/inouts
19056     0/imm32/no-outputs
19057     0/imm32/no-outputs
19058     0x11/imm32/alloc-id:fake
19059     _string_c1_subop_shift_left/imm32/subx-name
19060     1/imm32/rm32-is-first-inout
19061     0/imm32/no-r32
19062     0/imm32/no-imm32
19063     2/imm32/imm8-is-second-inout
19064     0/imm32/no-disp32
19065     0/imm32/no-xm32
19066     0/imm32/no-x32
19067     0x11/imm32/alloc-id:fake
19068     _Primitive-shift-mem-right-by-lit/imm32/next
19069 _Primitive-shift-mem-right-by-lit:  # (payload primitive)
19070     0x11/imm32/alloc-id:fake:payload
19071     # shift-right var1, lit => c1/shift 5/subop/right var1/rm32 lit/imm32
19072     0x11/imm32/alloc-id:fake
19073     _string-shift-right/imm32/name
19074     0x11/imm32/alloc-id:fake
19075     Int-var-and-literal/imm32/inouts
19076     0/imm32/no-outputs
19077     0/imm32/no-outputs
19078     0x11/imm32/alloc-id:fake
19079     _string_c1_subop_shift_right_padding_zeroes/imm32/subx-name
19080     1/imm32/rm32-is-first-inout
19081     0/imm32/no-r32
19082     0/imm32/no-imm32
19083     2/imm32/imm8-is-second-inout
19084     0/imm32/no-disp32
19085     0/imm32/no-xm32
19086     0/imm32/no-x32
19087     0x11/imm32/alloc-id:fake
19088     _Primitive-shift-mem-right-signed-by-lit/imm32/next
19089 _Primitive-shift-mem-right-signed-by-lit:  # (payload primitive)
19090     0x11/imm32/alloc-id:fake:payload
19091     # shift-right-signed var1, lit => c1/shift 7/subop/right-preserving-sign var1/rm32 lit/imm32
19092     0x11/imm32/alloc-id:fake
19093     _string-shift-right-signed/imm32/name
19094     0x11/imm32/alloc-id:fake
19095     Int-var-and-literal/imm32/inouts
19096     0/imm32/no-outputs
19097     0/imm32/no-outputs
19098     0x11/imm32/alloc-id:fake
19099     _string_c1_subop_shift_right_preserving_sign/imm32/subx-name
19100     1/imm32/rm32-is-first-inout
19101     0/imm32/no-r32
19102     0/imm32/no-imm32
19103     2/imm32/imm8-is-second-inout
19104     0/imm32/no-disp32
19105     0/imm32/no-xm32
19106     0/imm32/no-x32
19107     0x11/imm32/alloc-id:fake
19108     _Primitive-copy-to-eax/imm32/next
19109 # - copy
19110 _Primitive-copy-to-eax:  # (payload primitive)
19111     0x11/imm32/alloc-id:fake:payload
19112     # var/eax <- copy lit => b8/copy-to-eax lit/imm32
19113     0x11/imm32/alloc-id:fake
19114     _string-copy/imm32/name
19115     0x11/imm32/alloc-id:fake
19116     Single-lit-var/imm32/inouts
19117     0x11/imm32/alloc-id:fake
19118     Single-int-var-in-eax/imm32/outputs
19119     0x11/imm32/alloc-id:fake
19120     _string_b8_copy_to_eax/imm32/subx-name
19121     0/imm32/no-rm32
19122     0/imm32/no-r32
19123     1/imm32/imm32-is-first-inout
19124     0/imm32/no-imm8
19125     0/imm32/no-disp32
19126     0/imm32/no-xm32
19127     0/imm32/no-x32
19128     0x11/imm32/alloc-id:fake
19129     _Primitive-copy-to-ecx/imm32/next
19130 _Primitive-copy-to-ecx:  # (payload primitive)
19131     0x11/imm32/alloc-id:fake:payload
19132     # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32
19133     0x11/imm32/alloc-id:fake
19134     _string-copy/imm32/name
19135     0x11/imm32/alloc-id:fake
19136     Single-lit-var/imm32/inouts
19137     0x11/imm32/alloc-id:fake
19138     Single-int-var-in-ecx/imm32/outputs
19139     0x11/imm32/alloc-id:fake
19140     _string_b9_copy_to_ecx/imm32/subx-name
19141     0/imm32/no-rm32
19142     0/imm32/no-r32
19143     1/imm32/imm32-is-first-inout
19144     0/imm32/no-imm8
19145     0/imm32/no-disp32
19146     0/imm32/no-xm32
19147     0/imm32/no-x32
19148     0x11/imm32/alloc-id:fake
19149     _Primitive-copy-to-edx/imm32/next
19150 _Primitive-copy-to-edx:  # (payload primitive)
19151     0x11/imm32/alloc-id:fake:payload
19152     # var/edx <- copy lit => ba/copy-to-edx lit/imm32
19153     0x11/imm32/alloc-id:fake
19154     _string-copy/imm32/name
19155     0x11/imm32/alloc-id:fake
19156     Single-lit-var/imm32/inouts
19157     0x11/imm32/alloc-id:fake
19158     Single-int-var-in-edx/imm32/outputs
19159     0x11/imm32/alloc-id:fake
19160     _string_ba_copy_to_edx/imm32/subx-name
19161     0/imm32/no-rm32
19162     0/imm32/no-r32
19163     1/imm32/imm32-is-first-inout
19164     0/imm32/no-imm8
19165     0/imm32/no-disp32
19166     0/imm32/no-xm32
19167     0/imm32/no-x32
19168     0x11/imm32/alloc-id:fake
19169     _Primitive-copy-to-ebx/imm32/next
19170 _Primitive-copy-to-ebx:  # (payload primitive)
19171     0x11/imm32/alloc-id:fake:payload
19172     # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32
19173     0x11/imm32/alloc-id:fake
19174     _string-copy/imm32/name
19175     0x11/imm32/alloc-id:fake
19176     Single-lit-var/imm32/inouts
19177     0x11/imm32/alloc-id:fake
19178     Single-int-var-in-ebx/imm32/outputs
19179     0x11/imm32/alloc-id:fake
19180     _string_bb_copy_to_ebx/imm32/subx-name
19181     0/imm32/no-rm32
19182     0/imm32/no-r32
19183     1/imm32/imm32-is-first-inout
19184     0/imm32/no-imm8
19185     0/imm32/no-disp32
19186     0/imm32/no-xm32
19187     0/imm32/no-x32
19188     0x11/imm32/alloc-id:fake
19189     _Primitive-copy-to-esi/imm32/next
19190 _Primitive-copy-to-esi:  # (payload primitive)
19191     0x11/imm32/alloc-id:fake:payload
19192     # var/esi <- copy lit => be/copy-to-esi lit/imm32
19193     0x11/imm32/alloc-id:fake
19194     _string-copy/imm32/name
19195     0x11/imm32/alloc-id:fake
19196     Single-lit-var/imm32/inouts
19197     0x11/imm32/alloc-id:fake
19198     Single-int-var-in-esi/imm32/outputs
19199     0x11/imm32/alloc-id:fake
19200     _string_be_copy_to_esi/imm32/subx-name
19201     0/imm32/no-rm32
19202     0/imm32/no-r32
19203     1/imm32/imm32-is-first-inout
19204     0/imm32/no-imm8
19205     0/imm32/no-disp32
19206     0/imm32/no-xm32
19207     0/imm32/no-x32
19208     0x11/imm32/alloc-id:fake
19209     _Primitive-copy-to-edi/imm32/next
19210 _Primitive-copy-to-edi:  # (payload primitive)
19211     0x11/imm32/alloc-id:fake:payload
19212     # var/edi <- copy lit => bf/copy-to-edi lit/imm32
19213     0x11/imm32/alloc-id:fake
19214     _string-copy/imm32/name
19215     0x11/imm32/alloc-id:fake
19216     Single-lit-var/imm32/inouts
19217     0x11/imm32/alloc-id:fake
19218     Single-int-var-in-edi/imm32/outputs
19219     0x11/imm32/alloc-id:fake
19220     _string_bf_copy_to_edi/imm32/subx-name
19221     0/imm32/no-rm32
19222     0/imm32/no-r32
19223     1/imm32/imm32-is-first-inout
19224     0/imm32/no-imm8
19225     0/imm32/no-disp32
19226     0/imm32/no-xm32
19227     0/imm32/no-x32
19228     0x11/imm32/alloc-id:fake
19229     _Primitive-copy-reg-to-reg/imm32/next
19230 _Primitive-copy-reg-to-reg:  # (payload primitive)
19231     0x11/imm32/alloc-id:fake:payload
19232     # var1/reg <- copy var2/reg => 89/<- var1/rm32 var2/r32
19233     0x11/imm32/alloc-id:fake
19234     _string-copy/imm32/name
19235     0x11/imm32/alloc-id:fake
19236     Single-int-var-in-some-register/imm32/inouts
19237     0x11/imm32/alloc-id:fake
19238     Single-int-var-in-some-register/imm32/outputs
19239     0x11/imm32/alloc-id:fake
19240     _string_89_<-/imm32/subx-name
19241     3/imm32/rm32-is-first-output
19242     1/imm32/r32-is-first-inout
19243     0/imm32/no-imm32
19244     0/imm32/no-imm8
19245     0/imm32/no-disp32
19246     0/imm32/no-xm32
19247     0/imm32/no-x32
19248     0x11/imm32/alloc-id:fake
19249     _Primitive-copy-reg-to-mem/imm32/next
19250 _Primitive-copy-reg-to-mem:  # (payload primitive)
19251     0x11/imm32/alloc-id:fake:payload
19252     # copy-to var1 var2/reg => 89/<- var1 var2/r32
19253     0x11/imm32/alloc-id:fake
19254     _string-copy-to/imm32/name
19255     0x11/imm32/alloc-id:fake
19256     Two-args-int-stack-int-reg/imm32/inouts
19257     0/imm32/no-outputs
19258     0/imm32/no-outputs
19259     0x11/imm32/alloc-id:fake
19260     _string_89_<-/imm32/subx-name
19261     1/imm32/rm32-is-first-inout
19262     2/imm32/r32-is-second-inout
19263     0/imm32/no-imm32
19264     0/imm32/no-imm8
19265     0/imm32/no-disp32
19266     0/imm32/no-xm32
19267     0/imm32/no-x32
19268     0x11/imm32/alloc-id:fake
19269     _Primitive-copy-mem-to-reg/imm32/next
19270 _Primitive-copy-mem-to-reg:  # (payload primitive)
19271     0x11/imm32/alloc-id:fake:payload
19272     # var1/reg <- copy var2 => 8b/-> var2/rm32 var1/r32
19273     0x11/imm32/alloc-id:fake
19274     _string-copy/imm32/name
19275     0x11/imm32/alloc-id:fake
19276     Single-int-var-in-mem/imm32/inouts
19277     0x11/imm32/alloc-id:fake
19278     Single-int-var-in-some-register/imm32/outputs
19279     0x11/imm32/alloc-id:fake
19280     _string_8b_->/imm32/subx-name
19281     1/imm32/rm32-is-first-inout
19282     3/imm32/r32-is-first-output
19283     0/imm32/no-imm32
19284     0/imm32/no-imm8
19285     0/imm32/no-disp32
19286     0/imm32/no-xm32
19287     0/imm32/no-x32
19288     0x11/imm32/alloc-id:fake
19289     _Primitive-copy-lit-to-reg/imm32/next
19290 _Primitive-copy-lit-to-reg:  # (payload primitive)
19291     0x11/imm32/alloc-id:fake:payload
19292     # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32
19293     0x11/imm32/alloc-id:fake
19294     _string-copy/imm32/name
19295     0x11/imm32/alloc-id:fake
19296     Single-lit-var/imm32/inouts
19297     0x11/imm32/alloc-id:fake
19298     Single-int-var-in-some-register/imm32/outputs
19299     0x11/imm32/alloc-id:fake
19300     _string_c7_subop_copy/imm32/subx-name
19301     3/imm32/rm32-is-first-output
19302     0/imm32/no-r32
19303     1/imm32/imm32-is-first-inout
19304     0/imm32/no-imm8
19305     0/imm32/no-disp32
19306     0/imm32/no-xm32
19307     0/imm32/no-x32
19308     0x11/imm32/alloc-id:fake
19309     _Primitive-copy-lit-to-mem/imm32/next
19310 _Primitive-copy-lit-to-mem:  # (payload primitive)
19311     0x11/imm32/alloc-id:fake:payload
19312     # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32
19313     0x11/imm32/alloc-id:fake
19314     _string-copy-to/imm32/name
19315     0x11/imm32/alloc-id:fake
19316     Int-var-and-literal/imm32/inouts
19317     0/imm32/no-outputs
19318     0/imm32/no-outputs
19319     0x11/imm32/alloc-id:fake
19320     _string_c7_subop_copy/imm32/subx-name
19321     1/imm32/rm32-is-first-inout
19322     0/imm32/no-r32
19323     2/imm32/imm32-is-second-inout
19324     0/imm32/no-imm8
19325     0/imm32/no-disp32
19326     0/imm32/no-xm32
19327     0/imm32/no-x32
19328     0x11/imm32/alloc-id:fake
19329     _Primitive-copy-byte-from-reg/imm32/next
19330 # - copy byte
19331 _Primitive-copy-byte-from-reg:
19332     0x11/imm32/alloc-id:fake:payload
19333     # var/reg <- copy-byte var2/reg2 => 8a/byte-> %var2 var/r32
19334     0x11/imm32/alloc-id:fake
19335     _string-copy-byte/imm32/name
19336     0x11/imm32/alloc-id:fake
19337     Single-byte-var-in-some-register/imm32/inouts
19338     0x11/imm32/alloc-id:fake
19339     Single-byte-var-in-some-register/imm32/outputs
19340     0x11/imm32/alloc-id:fake
19341     _string_8a_copy_byte/imm32/subx-name
19342     1/imm32/rm32-is-first-inout
19343     3/imm32/r32-is-first-output
19344     0/imm32/no-imm32
19345     0/imm32/no-imm8
19346     0/imm32/no-disp32
19347     0/imm32/no-xm32
19348     0/imm32/no-x32
19349     0x11/imm32/alloc-id:fake
19350     _Primitive-copy-byte-from-mem/imm32/next
19351 _Primitive-copy-byte-from-mem:
19352     0x11/imm32/alloc-id:fake:payload
19353     # var/reg <- copy-byte *var2/reg2 => 8a/byte-> *var2 var/r32
19354     0x11/imm32/alloc-id:fake
19355     _string-copy-byte/imm32/name
19356     0x11/imm32/alloc-id:fake
19357     Single-byte-var-in-mem/imm32/inouts
19358     0x11/imm32/alloc-id:fake
19359     Single-byte-var-in-some-register/imm32/outputs
19360     0x11/imm32/alloc-id:fake
19361     _string_8a_copy_byte/imm32/subx-name
19362     1/imm32/rm32-is-first-inout
19363     3/imm32/r32-is-first-output
19364     0/imm32/no-imm32
19365     0/imm32/no-imm8
19366     0/imm32/no-disp32
19367     0/imm32/no-xm32
19368     0/imm32/no-x32
19369     0x11/imm32/alloc-id:fake
19370     _Primitive-copy-byte-to-mem/imm32/next
19371 _Primitive-copy-byte-to-mem:
19372     0x11/imm32/alloc-id:fake:payload
19373     # copy-byte-to *var1/reg1, var2/reg2 => 88/byte<- *reg1 reg2/r32
19374     0x11/imm32/alloc-id:fake
19375     _string-copy-byte-to/imm32/name
19376     0x11/imm32/alloc-id:fake
19377     Two-args-byte-stack-byte-reg/imm32/inouts
19378     0/imm32/no-outputs
19379     0/imm32/no-outputs
19380     0x11/imm32/alloc-id:fake
19381     _string_88_copy_byte/imm32/subx-name
19382     1/imm32/rm32-is-first-inout
19383     2/imm32/r32-is-second-inout
19384     0/imm32/no-imm32
19385     0/imm32/no-imm8
19386     0/imm32/no-disp32
19387     0/imm32/no-xm32
19388     0/imm32/no-x32
19389     0x11/imm32/alloc-id:fake
19390     _Primitive-address/imm32/next
19391 # - address
19392 _Primitive-address:  # (payload primitive)
19393     0x11/imm32/alloc-id:fake:payload
19394     # var1/reg <- address var2 => 8d/copy-address var2/rm32 var1/r32
19395     0x11/imm32/alloc-id:fake
19396     _string-address/imm32/name
19397     0x11/imm32/alloc-id:fake
19398     Single-int-var-in-mem/imm32/inouts
19399     0x11/imm32/alloc-id:fake
19400     Single-addr-var-in-some-register/imm32/outputs
19401     0x11/imm32/alloc-id:fake
19402     _string_8d_copy_address/imm32/subx-name
19403     1/imm32/rm32-is-first-inout
19404     3/imm32/r32-is-first-output
19405     0/imm32/no-imm32
19406     0/imm32/no-imm8
19407     0/imm32/no-disp32
19408     0/imm32/no-xm32
19409     0/imm32/no-x32
19410     0x11/imm32/alloc-id:fake
19411     _Primitive-compare-reg-with-reg/imm32/next
19412 # - compare
19413 _Primitive-compare-reg-with-reg:  # (payload primitive)
19414     0x11/imm32/alloc-id:fake:payload
19415     # compare var1/reg1 var2/reg2 => 39/compare var1/rm32 var2/r32
19416     0x11/imm32/alloc-id:fake
19417     _string-compare/imm32/name
19418     0x11/imm32/alloc-id:fake
19419     Two-int-args-in-regs/imm32/inouts
19420     0/imm32/no-outputs
19421     0/imm32/no-outputs
19422     0x11/imm32/alloc-id:fake
19423     _string_39_compare->/imm32/subx-name
19424     1/imm32/rm32-is-first-inout
19425     2/imm32/r32-is-second-inout
19426     0/imm32/no-imm32
19427     0/imm32/no-imm8
19428     0/imm32/no-disp32
19429     0/imm32/no-xm32
19430     0/imm32/no-x32
19431     0x11/imm32/alloc-id:fake
19432     _Primitive-compare-mem-with-reg/imm32/next
19433 _Primitive-compare-mem-with-reg:  # (payload primitive)
19434     0x11/imm32/alloc-id:fake:payload
19435     # compare var1 var2/reg => 39/compare var1/rm32 var2/r32
19436     0x11/imm32/alloc-id:fake
19437     _string-compare/imm32/name
19438     0x11/imm32/alloc-id:fake
19439     Two-args-int-stack-int-reg/imm32/inouts
19440     0/imm32/no-outputs
19441     0/imm32/no-outputs
19442     0x11/imm32/alloc-id:fake
19443     _string_39_compare->/imm32/subx-name
19444     1/imm32/rm32-is-first-inout
19445     2/imm32/r32-is-second-inout
19446     0/imm32/no-imm32
19447     0/imm32/no-imm8
19448     0/imm32/no-disp32
19449     0/imm32/no-xm32
19450     0/imm32/no-x32
19451     0x11/imm32/alloc-id:fake
19452     _Primitive-compare-reg-with-mem/imm32/next
19453 _Primitive-compare-reg-with-mem:  # (payload primitive)
19454     0x11/imm32/alloc-id:fake:payload
19455     # compare var1/reg var2 => 3b/compare<- var2/rm32 var1/r32
19456     0x11/imm32/alloc-id:fake
19457     _string-compare/imm32/name
19458     0x11/imm32/alloc-id:fake
19459     Two-args-int-reg-int-stack/imm32/inouts
19460     0/imm32/no-outputs
19461     0/imm32/no-outputs
19462     0x11/imm32/alloc-id:fake
19463     _string_3b_compare<-/imm32/subx-name
19464     2/imm32/rm32-is-second-inout
19465     1/imm32/r32-is-first-inout
19466     0/imm32/no-imm32
19467     0/imm32/no-imm8
19468     0/imm32/no-disp32
19469     0/imm32/no-xm32
19470     0/imm32/no-x32
19471     0x11/imm32/alloc-id:fake
19472     _Primitive-compare-eax-with-literal/imm32/next
19473 _Primitive-compare-eax-with-literal:  # (payload primitive)
19474     0x11/imm32/alloc-id:fake:payload
19475     # compare var1/eax n => 3d/compare-eax-with n/imm32
19476     0x11/imm32/alloc-id:fake
19477     _string-compare/imm32/name
19478     0x11/imm32/alloc-id:fake
19479     Two-args-int-eax-int-literal/imm32/inouts
19480     0/imm32/no-outputs
19481     0/imm32/no-outputs
19482     0x11/imm32/alloc-id:fake
19483     _string_3d_compare_eax_with/imm32/subx-name
19484     0/imm32/no-rm32
19485     0/imm32/no-r32
19486     2/imm32/imm32-is-second-inout
19487     0/imm32/no-imm8
19488     0/imm32/no-disp32
19489     0/imm32/no-xm32
19490     0/imm32/no-x32
19491     0x11/imm32/alloc-id:fake
19492     _Primitive-compare-reg-with-literal/imm32/next
19493 _Primitive-compare-reg-with-literal:  # (payload primitive)
19494     0x11/imm32/alloc-id:fake:payload
19495     # compare var1/reg n => 81 7/subop/compare %reg n/imm32
19496     0x11/imm32/alloc-id:fake
19497     _string-compare/imm32/name
19498     0x11/imm32/alloc-id:fake
19499     Int-var-in-register-and-literal/imm32/inouts
19500     0/imm32/no-outputs
19501     0/imm32/no-outputs
19502     0x11/imm32/alloc-id:fake
19503     _string_81_subop_compare/imm32/subx-name
19504     1/imm32/rm32-is-first-inout
19505     0/imm32/no-r32
19506     2/imm32/imm32-is-second-inout
19507     0/imm32/no-imm8
19508     0/imm32/no-disp32
19509     0/imm32/no-xm32
19510     0/imm32/no-x32
19511     0x11/imm32/alloc-id:fake
19512     _Primitive-compare-mem-with-literal/imm32/next
19513 _Primitive-compare-mem-with-literal:  # (payload primitive)
19514     0x11/imm32/alloc-id:fake:payload
19515     # compare var1 n => 81 7/subop/compare *(ebp+___) n/imm32
19516     0x11/imm32/alloc-id:fake
19517     _string-compare/imm32/name
19518     0x11/imm32/alloc-id:fake
19519     Int-var-and-literal/imm32/inouts
19520     0/imm32/no-outputs
19521     0/imm32/no-outputs
19522     0x11/imm32/alloc-id:fake
19523     _string_81_subop_compare/imm32/subx-name
19524     1/imm32/rm32-is-first-inout
19525     0/imm32/no-r32
19526     2/imm32/imm32-is-second-inout
19527     0/imm32/no-imm8
19528     0/imm32/no-disp32
19529     0/imm32/no-xm32
19530     0/imm32/no-x32
19531     0x11/imm32/alloc-id:fake
19532     _Primitive-negate-reg/imm32/next
19533 # - negate
19534 _Primitive-negate-reg:  # (payload primitive)
19535     0x11/imm32/alloc-id:fake:payload
19536     # var1/reg <- negate => f7 3/subop/negate var1/rm32
19537     0x11/imm32/alloc-id:fake
19538     _string-negate/imm32/name
19539     0/imm32/no-inouts
19540     0/imm32/no-inouts
19541     0x11/imm32/alloc-id:fake
19542     Single-int-var-in-some-register/imm32/outputs
19543     0x11/imm32/alloc-id:fake
19544     _string_f7_subop_negate/imm32/subx-name
19545     3/imm32/rm32-is-first-output
19546     0/imm32/no-r32
19547     0/imm32/no-imm32
19548     0/imm32/no-imm8
19549     0/imm32/no-disp32
19550     0/imm32/no-xm32
19551     0/imm32/no-x32
19552     0x11/imm32/alloc-id:fake
19553     _Primitive-negate-mem/imm32/next
19554 _Primitive-negate-mem:  # (payload primitive)
19555     0x11/imm32/alloc-id:fake:payload
19556     # negate var1 => f7 3/subop/negate var1/rm32
19557     0x11/imm32/alloc-id:fake
19558     _string-negate/imm32/name
19559     0x11/imm32/alloc-id:fake
19560     Single-int-var-in-mem/imm32/inouts
19561     0/imm32/no-outputs
19562     0/imm32/no-outputs
19563     0x11/imm32/alloc-id:fake
19564     _string_f7_subop_negate/imm32/subx-name
19565     1/imm32/rm32-is-first-inout
19566     0/imm32/no-r32
19567     0/imm32/no-imm32
19568     0/imm32/no-imm8
19569     0/imm32/no-disp32
19570     0/imm32/no-xm32
19571     0/imm32/no-x32
19572     0x11/imm32/alloc-id:fake
19573     _Primitive-multiply-reg-by-reg/imm32/next
19574 # - multiply
19575 _Primitive-multiply-reg-by-reg:  # (payload primitive)
19576     0x11/imm32/alloc-id:fake:payload
19577     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
19578     0x11/imm32/alloc-id:fake
19579     _string-multiply/imm32/name
19580     0x11/imm32/alloc-id:fake
19581     Single-int-var-in-some-register/imm32/inouts
19582     0x11/imm32/alloc-id:fake
19583     Single-int-var-in-some-register/imm32/outputs
19584     0x11/imm32/alloc-id:fake
19585     _string_0f_af_multiply/imm32/subx-name
19586     1/imm32/rm32-is-first-inout
19587     3/imm32/r32-is-first-output
19588     0/imm32/no-imm32
19589     0/imm32/no-imm8
19590     0/imm32/no-disp32
19591     0/imm32/no-xm32
19592     0/imm32/no-x32
19593     0x11/imm32/alloc-id:fake
19594     _Primitive-multiply-reg-by-mem/imm32/next
19595 _Primitive-multiply-reg-by-mem:  # (payload primitive)
19596     0x11/imm32/alloc-id:fake:payload
19597     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
19598     0x11/imm32/alloc-id:fake
19599     _string-multiply/imm32/name
19600     0x11/imm32/alloc-id:fake
19601     Single-int-var-in-mem/imm32/inouts
19602     0x11/imm32/alloc-id:fake
19603     Single-int-var-in-some-register/imm32/outputs
19604     0x11/imm32/alloc-id:fake
19605     _string_0f_af_multiply/imm32/subx-name
19606     1/imm32/rm32-is-first-inout
19607     3/imm32/r32-is-first-output
19608     0/imm32/no-imm32
19609     0/imm32/no-imm8
19610     0/imm32/no-disp32
19611     0/imm32/no-xm32
19612     0/imm32/no-x32
19613     0x11/imm32/alloc-id:fake
19614     _Primitive-convert-mem-to-xreg/imm32/next
19615 # - convert int to floating point
19616 _Primitive-convert-mem-to-xreg:  # (payload primitive)
19617     0x11/imm32/alloc-id:fake:payload
19618     # var1/xreg <- convert var2 => f3 0f 2a/convert-to-float var2/rm32 var1/x32
19619     0x11/imm32/alloc-id:fake
19620     _string-convert/imm32/name
19621     0x11/imm32/alloc-id:fake
19622     Single-int-var-in-mem/imm32/inouts
19623     0x11/imm32/alloc-id:fake
19624     Single-float-var-in-some-register/imm32/outputs
19625     0x11/imm32/alloc-id:fake
19626     _string_f3_0f_2a_convert_to_float/imm32/subx-name
19627     1/imm32/rm32-is-first-inout
19628     0/imm32/no-r32
19629     0/imm32/no-imm32
19630     0/imm32/no-imm8
19631     0/imm32/no-disp32
19632     0/imm32/no-xm32
19633     3/imm32/x32-is-first-output
19634     0x11/imm32/alloc-id:fake
19635     _Primitive-convert-reg-to-xreg/imm32/next
19636 _Primitive-convert-reg-to-xreg:  # (payload primitive)
19637     0x11/imm32/alloc-id:fake:payload
19638     # var1/xreg <- convert var2/reg => f3 0f 2a/convert-to-float var2/rm32 var1/x32
19639     0x11/imm32/alloc-id:fake
19640     _string-convert/imm32/name
19641     0x11/imm32/alloc-id:fake
19642     Single-int-var-in-some-register/imm32/inouts
19643     0x11/imm32/alloc-id:fake
19644     Single-float-var-in-some-register/imm32/outputs
19645     0x11/imm32/alloc-id:fake
19646     _string_f3_0f_2a_convert_to_float/imm32/subx-name
19647     1/imm32/rm32-is-first-inout
19648     0/imm32/no-r32
19649     0/imm32/no-imm32
19650     0/imm32/no-imm8
19651     0/imm32/no-disp32
19652     0/imm32/no-xm32
19653     3/imm32/x32-is-first-output
19654     0x11/imm32/alloc-id:fake
19655     _Primitive-convert-xmem-to-reg/imm32/next
19656 # - convert floating point to int
19657 _Primitive-convert-xmem-to-reg:  # (payload primitive)
19658     0x11/imm32/alloc-id:fake:payload
19659     # var1/reg <- convert var2 => f3 0f 2d/convert-to-int var2/xm32 var1/r32
19660     0x11/imm32/alloc-id:fake
19661     _string-convert/imm32/name
19662     0x11/imm32/alloc-id:fake
19663     Single-float-var-in-mem/imm32/inouts
19664     0x11/imm32/alloc-id:fake
19665     Single-int-var-in-some-register/imm32/outputs
19666     0x11/imm32/alloc-id:fake
19667     _string_f3_0f_2d_convert_to_int/imm32/subx-name
19668     0/imm32/no-rm32
19669     3/imm32/r32-is-first-output
19670     0/imm32/no-imm32
19671     0/imm32/no-imm8
19672     0/imm32/no-disp32
19673     1/imm32/xm32-is-first-inout
19674     0/imm32/no-x32
19675     0x11/imm32/alloc-id:fake
19676     _Primitive-convert-xreg-to-reg/imm32/next
19677 _Primitive-convert-xreg-to-reg:  # (payload primitive)
19678     0x11/imm32/alloc-id:fake:payload
19679     # var1/reg <- convert var2/xreg => f3 0f 2d/convert-to-int var2/xm32 var1/r32
19680     0x11/imm32/alloc-id:fake
19681     _string-convert/imm32/name
19682     0x11/imm32/alloc-id:fake
19683     Single-float-var-in-some-register/imm32/inouts
19684     0x11/imm32/alloc-id:fake
19685     Single-int-var-in-some-register/imm32/outputs
19686     0x11/imm32/alloc-id:fake
19687     _string_f3_0f_2d_convert_to_int/imm32/subx-name
19688     0/imm32/no-rm32
19689     3/imm32/r32-is-first-output
19690     0/imm32/no-imm32
19691     0/imm32/no-imm8
19692     0/imm32/no-disp32
19693     1/imm32/xm32-is-first-inout
19694     0/imm32/no-x32
19695     0x11/imm32/alloc-id:fake
19696     _Primitive-copy-xreg-to-xreg/imm32/next
19697 _Primitive-copy-xreg-to-xreg:  # (payload primitive)
19698     0x11/imm32/alloc-id:fake:payload
19699     # var1/xreg <- copy var2/xreg => f3 0f 11/<- var1/xm32 var2/x32
19700     0x11/imm32/alloc-id:fake
19701     _string-copy/imm32/name
19702     0x11/imm32/alloc-id:fake
19703     Single-float-var-in-some-register/imm32/inouts
19704     0x11/imm32/alloc-id:fake
19705     Single-float-var-in-some-register/imm32/outputs
19706     0x11/imm32/alloc-id:fake
19707     _string_f3_0f_11_copy/imm32/subx-name
19708     0/imm32/no-rm32
19709     0/imm32/no-r32
19710     0/imm32/no-imm32
19711     0/imm32/no-imm8
19712     0/imm32/no-disp32
19713     3/imm32/xm32-is-first-output
19714     1/imm32/x32-is-first-inout
19715     0x11/imm32/alloc-id:fake
19716     _Primitive-copy-xreg-to-mem/imm32/next
19717 _Primitive-copy-xreg-to-mem:  # (payload primitive)
19718     0x11/imm32/alloc-id:fake:payload
19719     # copy-to var1 var2/xreg => f3 0f 11/<- var1 var2/x32
19720     0x11/imm32/alloc-id:fake
19721     _string-copy-to/imm32/name
19722     0x11/imm32/alloc-id:fake
19723     Two-args-float-stack-float-reg/imm32/inouts
19724     0/imm32/no-outputs
19725     0/imm32/no-outputs
19726     0x11/imm32/alloc-id:fake
19727     _string_f3_0f_11_copy/imm32/subx-name
19728     0/imm32/no-rm32
19729     0/imm32/no-r32
19730     0/imm32/no-imm32
19731     0/imm32/no-imm8
19732     0/imm32/no-disp32
19733     1/imm32/xm32-is-first-inout
19734     2/imm32/x32-is-second-inout
19735     0x11/imm32/alloc-id:fake
19736     _Primitive-copy-mem-to-xreg/imm32/next
19737 _Primitive-copy-mem-to-xreg:  # (payload primitive)
19738     0x11/imm32/alloc-id:fake:payload
19739     # var1/xreg <- copy var2 => f3 0f 10/-> var2/rm32 var1/x32
19740     0x11/imm32/alloc-id:fake
19741     _string-copy/imm32/name
19742     0x11/imm32/alloc-id:fake
19743     Single-float-var-in-mem/imm32/inouts
19744     0x11/imm32/alloc-id:fake
19745     Single-float-var-in-some-register/imm32/outputs
19746     0x11/imm32/alloc-id:fake
19747     _string_f3_0f_10_copy/imm32/subx-name
19748     0/imm32/no-rm32
19749     0/imm32/no-r32
19750     0/imm32/no-imm32
19751     0/imm32/no-imm8
19752     0/imm32/no-disp32
19753     1/imm32/xm32-is-first-inout
19754     3/imm32/x32-is-first-output
19755     0x11/imm32/alloc-id:fake
19756     _Primitive-add-xreg-to-xreg/imm32/next
19757 # add floats
19758 _Primitive-add-xreg-to-xreg:  # (payload primitive)
19759     0x11/imm32/alloc-id:fake:payload
19760     # var1/xreg <- add var2/xreg => f3 0f 58/add var1/xm32 var2/x32
19761     0x11/imm32/alloc-id:fake
19762     _string-add/imm32/name
19763     0x11/imm32/alloc-id:fake
19764     Single-float-var-in-some-register/imm32/inouts
19765     0x11/imm32/alloc-id:fake
19766     Single-float-var-in-some-register/imm32/outputs
19767     0x11/imm32/alloc-id:fake
19768     _string_f3_0f_58_add/imm32/subx-name
19769     0/imm32/no-rm32
19770     0/imm32/no-r32
19771     0/imm32/no-imm32
19772     0/imm32/no-imm8
19773     0/imm32/no-disp32
19774     1/imm32/xm32-is-first-inout
19775     3/imm32/x32-is-first-output
19776     0x11/imm32/alloc-id:fake
19777     _Primitive-add-mem-to-xreg/imm32/next
19778 _Primitive-add-mem-to-xreg:  # (payload primitive)
19779     0x11/imm32/alloc-id:fake:payload
19780     # var1/xreg <- add var2 => f3 0f 58/add var2/xm32 var1/x32
19781     0x11/imm32/alloc-id:fake
19782     _string-add/imm32/name
19783     0x11/imm32/alloc-id:fake
19784     Single-float-var-in-mem/imm32/inouts
19785     0x11/imm32/alloc-id:fake
19786     Single-float-var-in-some-register/imm32/outputs
19787     0x11/imm32/alloc-id:fake
19788     _string_f3_0f_58_add/imm32/subx-name
19789     0/imm32/no-rm32
19790     0/imm32/no-r32
19791     0/imm32/no-imm32
19792     0/imm32/no-imm8
19793     0/imm32/no-disp32
19794     1/imm32/xm32-is-first-inout
19795     3/imm32/x32-is-first-output
19796     0x11/imm32/alloc-id:fake
19797     _Primitive-subtract-xreg-from-xreg/imm32/next
19798 # subtract floats
19799 _Primitive-subtract-xreg-from-xreg:  # (payload primitive)
19800     0x11/imm32/alloc-id:fake:payload
19801     # var1/xreg <- subtract var2/xreg => f3 0f 5c/subtract var1/xm32 var2/x32
19802     0x11/imm32/alloc-id:fake
19803     _string-subtract/imm32/name
19804     0x11/imm32/alloc-id:fake
19805     Single-float-var-in-some-register/imm32/inouts
19806     0x11/imm32/alloc-id:fake
19807     Single-float-var-in-some-register/imm32/outputs
19808     0x11/imm32/alloc-id:fake
19809     _string_f3_0f_5c_subtract/imm32/subx-name
19810     0/imm32/no-rm32
19811     0/imm32/no-r32
19812     0/imm32/no-imm32
19813     0/imm32/no-imm8
19814     0/imm32/no-disp32
19815     1/imm32/xm32-is-first-inout
19816     3/imm32/x32-is-first-output
19817     0x11/imm32/alloc-id:fake
19818     _Primitive-subtract-mem-from-xreg/imm32/next
19819 _Primitive-subtract-mem-from-xreg:  # (payload primitive)
19820     0x11/imm32/alloc-id:fake:payload
19821     # var1/xreg <- subtract var2 => f3 0f 5c/subtract var2/xm32 var1/x32
19822     0x11/imm32/alloc-id:fake
19823     _string-subtract/imm32/name
19824     0x11/imm32/alloc-id:fake
19825     Single-float-var-in-mem/imm32/inouts
19826     0x11/imm32/alloc-id:fake
19827     Single-float-var-in-some-register/imm32/outputs
19828     0x11/imm32/alloc-id:fake
19829     _string_f3_0f_5c_subtract/imm32/subx-name
19830     0/imm32/no-rm32
19831     0/imm32/no-r32
19832     0/imm32/no-imm32
19833     0/imm32/no-imm8
19834     0/imm32/no-disp32
19835     1/imm32/xm32-is-first-inout
19836     3/imm32/x32-is-first-output
19837     0x11/imm32/alloc-id:fake
19838     _Primitive-multiply-xreg-by-xreg/imm32/next
19839 # - multiply
19840 _Primitive-multiply-xreg-by-xreg:  # (payload primitive)
19841     0x11/imm32/alloc-id:fake:payload
19842     # var1/xreg <- multiply var2 => f3 0f 59/multiply var2/xm32 var1/x32
19843     0x11/imm32/alloc-id:fake
19844     _string-multiply/imm32/name
19845     0x11/imm32/alloc-id:fake
19846     Single-float-var-in-some-register/imm32/inouts
19847     0x11/imm32/alloc-id:fake
19848     Single-float-var-in-some-register/imm32/outputs
19849     0x11/imm32/alloc-id:fake
19850     _string_f3_0f_59_multiply/imm32/subx-name
19851     0/imm32/no-rm32
19852     0/imm32/no-r32
19853     0/imm32/no-imm32
19854     0/imm32/no-imm8
19855     0/imm32/no-disp32
19856     1/imm32/xm32-is-first-inout
19857     3/imm32/x32-is-first-output
19858     0x11/imm32/alloc-id:fake
19859     _Primitive-multiply-xreg-by-mem/imm32/next
19860 _Primitive-multiply-xreg-by-mem:  # (payload primitive)
19861     0x11/imm32/alloc-id:fake:payload
19862     # var1/xreg <- multiply var2 => 53 0f 59/multiply var2/xm32 var1/x32
19863     0x11/imm32/alloc-id:fake
19864     _string-multiply/imm32/name
19865     0x11/imm32/alloc-id:fake
19866     Single-float-var-in-mem/imm32/inouts
19867     0x11/imm32/alloc-id:fake
19868     Single-float-var-in-some-register/imm32/outputs
19869     0x11/imm32/alloc-id:fake
19870     _string_f3_0f_59_multiply/imm32/subx-name
19871     0/imm32/no-rm32
19872     0/imm32/no-r32
19873     0/imm32/no-imm32
19874     0/imm32/no-imm8
19875     0/imm32/no-disp32
19876     1/imm32/xm32-is-first-inout
19877     3/imm32/x32-is-first-output
19878     0x11/imm32/alloc-id:fake
19879     _Primitive-divide-xreg-by-xreg/imm32/next
19880 # - divide
19881 _Primitive-divide-xreg-by-xreg:  # (payload primitive)
19882     0x11/imm32/alloc-id:fake:payload
19883     # var1/xreg <- divide var2 => f3 0f 5e/divide var2/xm32 var1/x32
19884     0x11/imm32/alloc-id:fake
19885     _string-divide/imm32/name
19886     0x11/imm32/alloc-id:fake
19887     Single-float-var-in-some-register/imm32/inouts
19888     0x11/imm32/alloc-id:fake
19889     Single-float-var-in-some-register/imm32/outputs
19890     0x11/imm32/alloc-id:fake
19891     _string_f3_0f_5e_divide/imm32/subx-name
19892     0/imm32/no-rm32
19893     0/imm32/no-r32
19894     0/imm32/no-imm32
19895     0/imm32/no-imm8
19896     0/imm32/no-disp32
19897     1/imm32/xm32-is-first-inout
19898     3/imm32/x32-is-first-output
19899     0x11/imm32/alloc-id:fake
19900     _Primitive-divide-xreg-by-mem/imm32/next
19901 _Primitive-divide-xreg-by-mem:  # (payload primitive)
19902     0x11/imm32/alloc-id:fake:payload
19903     # var1/xreg <- divide var2 => f3 0f 5e/divide var2/xm32 var1/x32
19904     0x11/imm32/alloc-id:fake
19905     _string-divide/imm32/name
19906     0x11/imm32/alloc-id:fake
19907     Single-float-var-in-mem/imm32/inouts
19908     0x11/imm32/alloc-id:fake
19909     Single-float-var-in-some-register/imm32/outputs
19910     0x11/imm32/alloc-id:fake
19911     _string_f3_0f_5e_divide/imm32/subx-name
19912     0/imm32/no-rm32
19913     0/imm32/no-r32
19914     0/imm32/no-imm32
19915     0/imm32/no-imm8
19916     0/imm32/no-disp32
19917     1/imm32/xm32-is-first-inout
19918     3/imm32/x32-is-first-output
19919     0x11/imm32/alloc-id:fake
19920     _Primitive-max-xreg-with-xreg/imm32/next
19921 # - maximum
19922 _Primitive-max-xreg-with-xreg:  # (payload primitive)
19923     0x11/imm32/alloc-id:fake:payload
19924     # var1/xreg <- max var2 => f3 0f 5f/max var2/xm32 var1/x32
19925     0x11/imm32/alloc-id:fake
19926     _string-max/imm32/name
19927     0x11/imm32/alloc-id:fake
19928     Single-float-var-in-some-register/imm32/inouts
19929     0x11/imm32/alloc-id:fake
19930     Single-float-var-in-some-register/imm32/outputs
19931     0x11/imm32/alloc-id:fake
19932     _string_f3_0f_5f_max/imm32/subx-name
19933     0/imm32/no-rm32
19934     0/imm32/no-r32
19935     0/imm32/no-imm32
19936     0/imm32/no-imm8
19937     0/imm32/no-disp32
19938     1/imm32/xm32-is-first-inout
19939     3/imm32/x32-is-first-output
19940     0x11/imm32/alloc-id:fake
19941     _Primitive-max-xreg-with-mem/imm32/next
19942 _Primitive-max-xreg-with-mem:  # (payload primitive)
19943     0x11/imm32/alloc-id:fake:payload
19944     # var1/xreg <- divide var2 => f3 0f 5f/max var2/xm32 var1/x32
19945     0x11/imm32/alloc-id:fake
19946     _string-max/imm32/name
19947     0x11/imm32/alloc-id:fake
19948     Single-float-var-in-mem/imm32/inouts
19949     0x11/imm32/alloc-id:fake
19950     Single-float-var-in-some-register/imm32/outputs
19951     0x11/imm32/alloc-id:fake
19952     _string_f3_0f_5f_max/imm32/subx-name
19953     0/imm32/no-rm32
19954     0/imm32/no-r32
19955     0/imm32/no-imm32
19956     0/imm32/no-imm8
19957     0/imm32/no-disp32
19958     1/imm32/xm32-is-first-inout
19959     3/imm32/x32-is-first-output
19960     0x11/imm32/alloc-id:fake
19961     _Primitive-min-xreg-with-xreg/imm32/next
19962 # - minimum
19963 _Primitive-min-xreg-with-xreg:  # (payload primitive)
19964     0x11/imm32/alloc-id:fake:payload
19965     # var1/xreg <- divide var2 => f3 0f 5d/min var2/xm32 var1/x32
19966     0x11/imm32/alloc-id:fake
19967     _string-min/imm32/name
19968     0x11/imm32/alloc-id:fake
19969     Single-float-var-in-some-register/imm32/inouts
19970     0x11/imm32/alloc-id:fake
19971     Single-float-var-in-some-register/imm32/outputs
19972     0x11/imm32/alloc-id:fake
19973     _string_f3_0f_5d_min/imm32/subx-name
19974     0/imm32/no-rm32
19975     0/imm32/no-r32
19976     0/imm32/no-imm32
19977     0/imm32/no-imm8
19978     0/imm32/no-disp32
19979     1/imm32/xm32-is-first-inout
19980     3/imm32/x32-is-first-output
19981     0x11/imm32/alloc-id:fake
19982     _Primitive-min-xreg-with-mem/imm32/next
19983 _Primitive-min-xreg-with-mem:  # (payload primitive)
19984     0x11/imm32/alloc-id:fake:payload
19985     # var1/xreg <- divide var2 => f3 0f 5d/min var2/xm32 var1/x32
19986     0x11/imm32/alloc-id:fake
19987     _string-min/imm32/name
19988     0x11/imm32/alloc-id:fake
19989     Single-float-var-in-mem/imm32/inouts
19990     0x11/imm32/alloc-id:fake
19991     Single-float-var-in-some-register/imm32/outputs
19992     0x11/imm32/alloc-id:fake
19993     _string_f3_0f_5d_min/imm32/subx-name
19994     0/imm32/no-rm32
19995     0/imm32/no-r32
19996     0/imm32/no-imm32
19997     0/imm32/no-imm8
19998     0/imm32/no-disp32
19999     1/imm32/xm32-is-first-inout
20000     3/imm32/x32-is-first-output
20001     0x11/imm32/alloc-id:fake
20002     _Primitive-reciprocal-xreg-to-xreg/imm32/next
20003 # - reciprocal
20004 _Primitive-reciprocal-xreg-to-xreg:  # (payload primitive)
20005     0x11/imm32/alloc-id:fake:payload
20006     # var1/xreg <- reciprocal var2 => f3 0f 53/reciprocal var2/xm32 var1/x32
20007     0x11/imm32/alloc-id:fake
20008     _string-reciprocal/imm32/name
20009     0x11/imm32/alloc-id:fake
20010     Single-float-var-in-some-register/imm32/inouts
20011     0x11/imm32/alloc-id:fake
20012     Single-float-var-in-some-register/imm32/outputs
20013     0x11/imm32/alloc-id:fake
20014     _string_f3_0f_53_reciprocal/imm32/subx-name
20015     0/imm32/no-rm32
20016     0/imm32/no-r32
20017     0/imm32/no-imm32
20018     0/imm32/no-imm8
20019     0/imm32/no-disp32
20020     1/imm32/xm32-is-first-inout
20021     3/imm32/x32-is-first-output
20022     0x11/imm32/alloc-id:fake
20023     _Primitive-reciprocal-mem-to-xreg/imm32/next
20024 _Primitive-reciprocal-mem-to-xreg:  # (payload primitive)
20025     0x11/imm32/alloc-id:fake:payload
20026     # var1/xreg <- divide var2 => f3 0f 53/reciprocal var2/xm32 var1/x32
20027     0x11/imm32/alloc-id:fake
20028     _string-reciprocal/imm32/name
20029     0x11/imm32/alloc-id:fake
20030     Single-float-var-in-mem/imm32/inouts
20031     0x11/imm32/alloc-id:fake
20032     Single-float-var-in-some-register/imm32/outputs
20033     0x11/imm32/alloc-id:fake
20034     _string_f3_0f_53_reciprocal/imm32/subx-name
20035     0/imm32/no-rm32
20036     0/imm32/no-r32
20037     0/imm32/no-imm32
20038     0/imm32/no-imm8
20039     0/imm32/no-disp32
20040     1/imm32/xm32-is-first-inout
20041     3/imm32/x32-is-first-output
20042     0x11/imm32/alloc-id:fake
20043     _Primitive-square-root-xreg-to-xreg/imm32/next
20044 # - square root
20045 _Primitive-square-root-xreg-to-xreg:  # (payload primitive)
20046     0x11/imm32/alloc-id:fake:payload
20047     # var1/xreg <- square-root var2 => f3 0f 51/square-root var2/xm32 var1/x32
20048     0x11/imm32/alloc-id:fake
20049     _string-square-root/imm32/name
20050     0x11/imm32/alloc-id:fake
20051     Single-float-var-in-some-register/imm32/inouts
20052     0x11/imm32/alloc-id:fake
20053     Single-float-var-in-some-register/imm32/outputs
20054     0x11/imm32/alloc-id:fake
20055     _string_f3_0f_51_square_root/imm32/subx-name
20056     0/imm32/no-rm32
20057     0/imm32/no-r32
20058     0/imm32/no-imm32
20059     0/imm32/no-imm8
20060     0/imm32/no-disp32
20061     1/imm32/xm32-is-first-inout
20062     3/imm32/x32-is-first-output
20063     0x11/imm32/alloc-id:fake
20064     _Primitive-square-root-mem-to-xreg/imm32/next
20065 _Primitive-square-root-mem-to-xreg:  # (payload primitive)
20066     0x11/imm32/alloc-id:fake:payload
20067     # var1/xreg <- divide var2 => f3 0f 51/square-root var2/xm32 var1/x32
20068     0x11/imm32/alloc-id:fake
20069     _string-square-root/imm32/name
20070     0x11/imm32/alloc-id:fake
20071     Single-float-var-in-mem/imm32/inouts
20072     0x11/imm32/alloc-id:fake
20073     Single-float-var-in-some-register/imm32/outputs
20074     0x11/imm32/alloc-id:fake
20075     _string_f3_0f_51_square_root/imm32/subx-name
20076     0/imm32/no-rm32
20077     0/imm32/no-r32
20078     0/imm32/no-imm32
20079     0/imm32/no-imm8
20080     0/imm32/no-disp32
20081     1/imm32/xm32-is-first-inout
20082     3/imm32/x32-is-first-output
20083     0x11/imm32/alloc-id:fake
20084     _Primitive-inverse-square-root-xreg-to-xreg/imm32/next
20085 # - inverse square root 1/sqrt(x)
20086 _Primitive-inverse-square-root-xreg-to-xreg:  # (payload primitive)
20087     0x11/imm32/alloc-id:fake:payload
20088     # var1/xreg <- reciprocal var2 => f3 0f 52/inverse-square-root var2/xm32 var1/x32
20089     0x11/imm32/alloc-id:fake
20090     _string-inverse-square-root/imm32/name
20091     0x11/imm32/alloc-id:fake
20092     Single-float-var-in-some-register/imm32/inouts
20093     0x11/imm32/alloc-id:fake
20094     Single-float-var-in-some-register/imm32/outputs
20095     0x11/imm32/alloc-id:fake
20096     _string_f3_0f_52_inverse_square_root/imm32/subx-name
20097     0/imm32/no-rm32
20098     0/imm32/no-r32
20099     0/imm32/no-imm32
20100     0/imm32/no-imm8
20101     0/imm32/no-disp32
20102     1/imm32/xm32-is-first-inout
20103     3/imm32/x32-is-first-output
20104     0x11/imm32/alloc-id:fake
20105     _Primitive-inverse-square-root-mem-to-xreg/imm32/next
20106 _Primitive-inverse-square-root-mem-to-xreg:  # (payload primitive)
20107     0x11/imm32/alloc-id:fake:payload
20108     # var1/xreg <- divide var2 => f3 0f 52/inverse-square-root var2/xm32 var1/x32
20109     0x11/imm32/alloc-id:fake
20110     _string-inverse-square-root/imm32/name
20111     0x11/imm32/alloc-id:fake
20112     Single-float-var-in-mem/imm32/inouts
20113     0x11/imm32/alloc-id:fake
20114     Single-float-var-in-some-register/imm32/outputs
20115     0x11/imm32/alloc-id:fake
20116     _string_f3_0f_52_inverse_square_root/imm32/subx-name
20117     0/imm32/no-rm32
20118     0/imm32/no-r32
20119     0/imm32/no-imm32
20120     0/imm32/no-imm8
20121     0/imm32/no-disp32
20122     1/imm32/xm32-is-first-inout
20123     3/imm32/x32-is-first-output
20124     0x11/imm32/alloc-id:fake
20125     _Primitive-compare-xreg-with-xreg/imm32/next
20126 # - compare
20127 _Primitive-compare-xreg-with-xreg:  # (payload primitive)
20128     0x11/imm32/alloc-id:fake:payload
20129     # compare var1/reg1 var2/reg2 => 0f 2f/compare var2/x32 var1/xm32
20130     0x11/imm32/alloc-id:fake
20131     _string-compare/imm32/name
20132     0x11/imm32/alloc-id:fake
20133     Two-float-args-in-regs/imm32/inouts
20134     0/imm32/no-outputs
20135     0/imm32/no-outputs
20136     0x11/imm32/alloc-id:fake
20137     _string_0f_2f_compare/imm32/subx-name
20138     0/imm32/no-rm32
20139     0/imm32/no-r32
20140     0/imm32/no-imm32
20141     0/imm32/no-imm8
20142     0/imm32/no-disp32
20143     1/imm32/xm32-is-first-inout
20144     2/imm32/x32-is-second-inout
20145     0x11/imm32/alloc-id:fake
20146     _Primitive-compare-xreg-with-mem/imm32/next
20147 _Primitive-compare-xreg-with-mem:  # (payload primitive)
20148     0x11/imm32/alloc-id:fake:payload
20149     # compare var1/xreg var2 => 0f 2f/compare var1/x32 var2/xm32
20150     0x11/imm32/alloc-id:fake
20151     _string-compare/imm32/name
20152     0x11/imm32/alloc-id:fake
20153     Two-args-float-reg-float-stack/imm32/inouts
20154     0/imm32/no-outputs
20155     0/imm32/no-outputs
20156     0x11/imm32/alloc-id:fake
20157     _string_0f_2f_compare/imm32/subx-name
20158     0/imm32/no-rm32
20159     0/imm32/no-r32
20160     0/imm32/no-imm32
20161     0/imm32/no-imm8
20162     0/imm32/no-disp32
20163     2/imm32/xm32-is-second-inout
20164     1/imm32/x32-is-first-inout
20165     0x11/imm32/alloc-id:fake
20166     _Primitive-break-if-addr</imm32/next
20167 # - branches
20168 _Primitive-break-if-addr<:  # (payload primitive)
20169     0x11/imm32/alloc-id:fake:payload
20170     0x11/imm32/alloc-id:fake
20171     _string-break-if-addr</imm32/name
20172     0/imm32/no-inouts
20173     0/imm32/no-inouts
20174     0/imm32/no-outputs
20175     0/imm32/no-outputs
20176     0x11/imm32/alloc-id:fake
20177     _string_0f_82_jump_break/imm32/subx-name
20178     0/imm32/no-rm32
20179     0/imm32/no-r32
20180     0/imm32/no-imm32
20181     0/imm32/no-imm8
20182     0/imm32/no-disp32
20183     0/imm32/no-xm32
20184     0/imm32/no-x32
20185     0x11/imm32/alloc-id:fake
20186     _Primitive-break-if-addr>=/imm32/next
20187 _Primitive-break-if-addr>=:  # (payload primitive)
20188     0x11/imm32/alloc-id:fake:payload
20189     0x11/imm32/alloc-id:fake
20190     _string-break-if-addr>=/imm32/name
20191     0/imm32/no-inouts
20192     0/imm32/no-inouts
20193     0/imm32/no-outputs
20194     0/imm32/no-outputs
20195     0x11/imm32/alloc-id:fake
20196     _string_0f_83_jump_break/imm32/subx-name
20197     0/imm32/no-rm32
20198     0/imm32/no-r32
20199     0/imm32/no-imm32
20200     0/imm32/no-imm8
20201     0/imm32/no-disp32
20202     0/imm32/no-xm32
20203     0/imm32/no-x32
20204     0x11/imm32/alloc-id:fake
20205     _Primitive-break-if-=/imm32/next
20206 _Primitive-break-if-=:  # (payload primitive)
20207     0x11/imm32/alloc-id:fake:payload
20208     0x11/imm32/alloc-id:fake
20209     _string-break-if-=/imm32/name
20210     0/imm32/no-inouts
20211     0/imm32/no-inouts
20212     0/imm32/no-outputs
20213     0/imm32/no-outputs
20214     0x11/imm32/alloc-id:fake
20215     _string_0f_84_jump_break/imm32/subx-name
20216     0/imm32/no-rm32
20217     0/imm32/no-r32
20218     0/imm32/no-imm32
20219     0/imm32/no-imm8
20220     0/imm32/no-disp32
20221     0/imm32/no-xm32
20222     0/imm32/no-x32
20223     0x11/imm32/alloc-id:fake
20224     _Primitive-break-if-!=/imm32/next
20225 _Primitive-break-if-!=:  # (payload primitive)
20226     0x11/imm32/alloc-id:fake:payload
20227     0x11/imm32/alloc-id:fake
20228     _string-break-if-!=/imm32/name
20229     0/imm32/no-inouts
20230     0/imm32/no-inouts
20231     0/imm32/no-outputs
20232     0/imm32/no-outputs
20233     0x11/imm32/alloc-id:fake
20234     _string_0f_85_jump_break/imm32/subx-name
20235     0/imm32/no-rm32
20236     0/imm32/no-r32
20237     0/imm32/no-imm32
20238     0/imm32/no-imm8
20239     0/imm32/no-disp32
20240     0/imm32/no-xm32
20241     0/imm32/no-x32
20242     0x11/imm32/alloc-id:fake
20243     _Primitive-break-if-addr<=/imm32/next
20244 _Primitive-break-if-addr<=:  # (payload primitive)
20245     0x11/imm32/alloc-id:fake:payload
20246     0x11/imm32/alloc-id:fake
20247     _string-break-if-addr<=/imm32/name
20248     0/imm32/no-inouts
20249     0/imm32/no-inouts
20250     0/imm32/no-outputs
20251     0/imm32/no-outputs
20252     0x11/imm32/alloc-id:fake
20253     _string_0f_86_jump_break/imm32/subx-name
20254     0/imm32/no-rm32
20255     0/imm32/no-r32
20256     0/imm32/no-imm32
20257     0/imm32/no-imm8
20258     0/imm32/no-disp32
20259     0/imm32/no-xm32
20260     0/imm32/no-x32
20261     0x11/imm32/alloc-id:fake
20262     _Primitive-break-if-addr>/imm32/next
20263 _Primitive-break-if-addr>:  # (payload primitive)
20264     0x11/imm32/alloc-id:fake:payload
20265     0x11/imm32/alloc-id:fake
20266     _string-break-if-addr>/imm32/name
20267     0/imm32/no-inouts
20268     0/imm32/no-inouts
20269     0/imm32/no-outputs
20270     0/imm32/no-outputs
20271     0x11/imm32/alloc-id:fake
20272     _string_0f_87_jump_break/imm32/subx-name
20273     0/imm32/no-rm32
20274     0/imm32/no-r32
20275     0/imm32/no-imm32
20276     0/imm32/no-imm8
20277     0/imm32/no-disp32
20278     0/imm32/no-xm32
20279     0/imm32/no-x32
20280     0x11/imm32/alloc-id:fake
20281     _Primitive-break-if-</imm32/next
20282 _Primitive-break-if-<:  # (payload primitive)
20283     0x11/imm32/alloc-id:fake:payload
20284     0x11/imm32/alloc-id:fake
20285     _string-break-if-</imm32/name
20286     0/imm32/no-inouts
20287     0/imm32/no-inouts
20288     0/imm32/no-outputs
20289     0/imm32/no-outputs
20290     0x11/imm32/alloc-id:fake
20291     _string_0f_8c_jump_break/imm32/subx-name
20292     0/imm32/no-rm32
20293     0/imm32/no-r32
20294     0/imm32/no-imm32
20295     0/imm32/no-imm8
20296     0/imm32/no-disp32
20297     0/imm32/no-xm32
20298     0/imm32/no-x32
20299     0x11/imm32/alloc-id:fake
20300     _Primitive-break-if->=/imm32/next
20301 _Primitive-break-if->=:  # (payload primitive)
20302     0x11/imm32/alloc-id:fake:payload
20303     0x11/imm32/alloc-id:fake
20304     _string-break-if->=/imm32/name
20305     0/imm32/no-inouts
20306     0/imm32/no-inouts
20307     0/imm32/no-outputs
20308     0/imm32/no-outputs
20309     0x11/imm32/alloc-id:fake
20310     _string_0f_8d_jump_break/imm32/subx-name
20311     0/imm32/no-rm32
20312     0/imm32/no-r32
20313     0/imm32/no-imm32
20314     0/imm32/no-imm8
20315     0/imm32/no-disp32
20316     0/imm32/no-xm32
20317     0/imm32/no-x32
20318     0x11/imm32/alloc-id:fake
20319     _Primitive-break-if-<=/imm32/next
20320 _Primitive-break-if-<=:  # (payload primitive)
20321     0x11/imm32/alloc-id:fake:payload
20322     0x11/imm32/alloc-id:fake
20323     _string-break-if-<=/imm32/name
20324     0/imm32/no-inouts
20325     0/imm32/no-inouts
20326     0/imm32/no-outputs
20327     0/imm32/no-outputs
20328     0x11/imm32/alloc-id:fake
20329     _string_0f_8e_jump_break/imm32/subx-name
20330     0/imm32/no-rm32
20331     0/imm32/no-r32
20332     0/imm32/no-imm32
20333     0/imm32/no-imm8
20334     0/imm32/no-disp32
20335     0/imm32/no-xm32
20336     0/imm32/no-x32
20337     0x11/imm32/alloc-id:fake
20338     _Primitive-break-if->/imm32/next
20339 _Primitive-break-if->:  # (payload primitive)
20340     0x11/imm32/alloc-id:fake:payload
20341     0x11/imm32/alloc-id:fake
20342     _string-break-if->/imm32/name
20343     0/imm32/no-inouts
20344     0/imm32/no-inouts
20345     0/imm32/no-outputs
20346     0/imm32/no-outputs
20347     0x11/imm32/alloc-id:fake
20348     _string_0f_8f_jump_break/imm32/subx-name
20349     0/imm32/no-rm32
20350     0/imm32/no-r32
20351     0/imm32/no-imm32
20352     0/imm32/no-imm8
20353     0/imm32/no-disp32
20354     0/imm32/no-xm32
20355     0/imm32/no-x32
20356     0x11/imm32/alloc-id:fake
20357     _Primitive-break/imm32/next
20358 _Primitive-break:  # (payload primitive)
20359     0x11/imm32/alloc-id:fake:payload
20360     0x11/imm32/alloc-id:fake
20361     _string-break/imm32/name
20362     0/imm32/no-inouts
20363     0/imm32/no-inouts
20364     0/imm32/no-outputs
20365     0/imm32/no-outputs
20366     0x11/imm32/alloc-id:fake
20367     _string_e9_jump_break/imm32/subx-name
20368     0/imm32/no-rm32
20369     0/imm32/no-r32
20370     0/imm32/no-imm32
20371     0/imm32/no-imm8
20372     0/imm32/no-disp32
20373     0/imm32/no-xm32
20374     0/imm32/no-x32
20375     0x11/imm32/alloc-id:fake
20376     _Primitive-loop-if-addr</imm32/next
20377 _Primitive-loop-if-addr<:  # (payload primitive)
20378     0x11/imm32/alloc-id:fake:payload
20379     0x11/imm32/alloc-id:fake
20380     _string-loop-if-addr</imm32/name
20381     0/imm32/no-inouts
20382     0/imm32/no-inouts
20383     0/imm32/no-outputs
20384     0/imm32/no-outputs
20385     0x11/imm32/alloc-id:fake
20386     _string_0f_82_jump_loop/imm32/subx-name
20387     0/imm32/no-rm32
20388     0/imm32/no-r32
20389     0/imm32/no-imm32
20390     0/imm32/no-imm8
20391     0/imm32/no-disp32
20392     0/imm32/no-xm32
20393     0/imm32/no-x32
20394     0x11/imm32/alloc-id:fake
20395     _Primitive-loop-if-addr>=/imm32/next
20396 _Primitive-loop-if-addr>=:  # (payload primitive)
20397     0x11/imm32/alloc-id:fake:payload
20398     0x11/imm32/alloc-id:fake
20399     _string-loop-if-addr>=/imm32/name
20400     0/imm32/no-inouts
20401     0/imm32/no-inouts
20402     0/imm32/no-outputs
20403     0/imm32/no-outputs
20404     0x11/imm32/alloc-id:fake
20405     _string_0f_83_jump_loop/imm32/subx-name
20406     0/imm32/no-rm32
20407     0/imm32/no-r32
20408     0/imm32/no-imm32
20409     0/imm32/no-imm8
20410     0/imm32/no-disp32
20411     0/imm32/no-xm32
20412     0/imm32/no-x32
20413     0x11/imm32/alloc-id:fake
20414     _Primitive-loop-if-=/imm32/next
20415 _Primitive-loop-if-=:  # (payload primitive)
20416     0x11/imm32/alloc-id:fake:payload
20417     0x11/imm32/alloc-id:fake
20418     _string-loop-if-=/imm32/name
20419     0/imm32/no-inouts
20420     0/imm32/no-inouts
20421     0/imm32/no-outputs
20422     0/imm32/no-outputs
20423     0x11/imm32/alloc-id:fake
20424     _string_0f_84_jump_loop/imm32/subx-name
20425     0/imm32/no-rm32
20426     0/imm32/no-r32
20427     0/imm32/no-imm32
20428     0/imm32/no-imm8
20429     0/imm32/no-disp32
20430     0/imm32/no-xm32
20431     0/imm32/no-x32
20432     0x11/imm32/alloc-id:fake
20433     _Primitive-loop-if-!=/imm32/next
20434 _Primitive-loop-if-!=:  # (payload primitive)
20435     0x11/imm32/alloc-id:fake:payload
20436     0x11/imm32/alloc-id:fake
20437     _string-loop-if-!=/imm32/name
20438     0/imm32/no-inouts
20439     0/imm32/no-inouts
20440     0/imm32/no-outputs
20441     0/imm32/no-outputs
20442     0x11/imm32/alloc-id:fake
20443     _string_0f_85_jump_loop/imm32/subx-name
20444     0/imm32/no-rm32
20445     0/imm32/no-r32
20446     0/imm32/no-imm32
20447     0/imm32/no-imm8
20448     0/imm32/no-disp32
20449     0/imm32/no-xm32
20450     0/imm32/no-x32
20451     0x11/imm32/alloc-id:fake
20452     _Primitive-loop-if-addr<=/imm32/next
20453 _Primitive-loop-if-addr<=:  # (payload primitive)
20454     0x11/imm32/alloc-id:fake:payload
20455     0x11/imm32/alloc-id:fake
20456     _string-loop-if-addr<=/imm32/name
20457     0/imm32/no-inouts
20458     0/imm32/no-inouts
20459     0/imm32/no-outputs
20460     0/imm32/no-outputs
20461     0x11/imm32/alloc-id:fake
20462     _string_0f_86_jump_loop/imm32/subx-name
20463     0/imm32/no-rm32
20464     0/imm32/no-r32
20465     0/imm32/no-imm32
20466     0/imm32/no-imm8
20467     0/imm32/no-disp32
20468     0/imm32/no-xm32
20469     0/imm32/no-x32
20470     0x11/imm32/alloc-id:fake
20471     _Primitive-loop-if-addr>/imm32/next
20472 _Primitive-loop-if-addr>:  # (payload primitive)
20473     0x11/imm32/alloc-id:fake:payload
20474     0x11/imm32/alloc-id:fake
20475     _string-loop-if-addr>/imm32/name
20476     0/imm32/no-inouts
20477     0/imm32/no-inouts
20478     0/imm32/no-outputs
20479     0/imm32/no-outputs
20480     0x11/imm32/alloc-id:fake
20481     _string_0f_87_jump_loop/imm32/subx-name
20482     0/imm32/no-rm32
20483     0/imm32/no-r32
20484     0/imm32/no-imm32
20485     0/imm32/no-imm8
20486     0/imm32/no-disp32
20487     0/imm32/no-xm32
20488     0/imm32/no-x32
20489     0x11/imm32/alloc-id:fake
20490     _Primitive-loop-if-</imm32/next
20491 _Primitive-loop-if-<:  # (payload primitive)
20492     0x11/imm32/alloc-id:fake:payload
20493     0x11/imm32/alloc-id:fake
20494     _string-loop-if-</imm32/name
20495     0/imm32/no-inouts
20496     0/imm32/no-inouts
20497     0/imm32/no-outputs
20498     0/imm32/no-outputs
20499     0x11/imm32/alloc-id:fake
20500     _string_0f_8c_jump_loop/imm32/subx-name
20501     0/imm32/no-rm32
20502     0/imm32/no-r32
20503     0/imm32/no-imm32
20504     0/imm32/no-imm8
20505     0/imm32/no-disp32
20506     0/imm32/no-xm32
20507     0/imm32/no-x32
20508     0x11/imm32/alloc-id:fake
20509     _Primitive-loop-if->=/imm32/next
20510 _Primitive-loop-if->=:  # (payload primitive)
20511     0x11/imm32/alloc-id:fake:payload
20512     0x11/imm32/alloc-id:fake
20513     _string-loop-if->=/imm32/name
20514     0/imm32/no-inouts
20515     0/imm32/no-inouts
20516     0/imm32/no-outputs
20517     0/imm32/no-outputs
20518     0x11/imm32/alloc-id:fake
20519     _string_0f_8d_jump_loop/imm32/subx-name
20520     0/imm32/no-rm32
20521     0/imm32/no-r32
20522     0/imm32/no-imm32
20523     0/imm32/no-imm8
20524     0/imm32/no-disp32
20525     0/imm32/no-xm32
20526     0/imm32/no-x32
20527     0x11/imm32/alloc-id:fake
20528     _Primitive-loop-if-<=/imm32/next
20529 _Primitive-loop-if-<=:  # (payload primitive)
20530     0x11/imm32/alloc-id:fake:payload
20531     0x11/imm32/alloc-id:fake
20532     _string-loop-if-<=/imm32/name
20533     0/imm32/no-inouts
20534     0/imm32/no-inouts
20535     0/imm32/no-outputs
20536     0/imm32/no-outputs
20537     0x11/imm32/alloc-id:fake
20538     _string_0f_8e_jump_loop/imm32/subx-name
20539     0/imm32/no-rm32
20540     0/imm32/no-r32
20541     0/imm32/no-imm32
20542     0/imm32/no-imm8
20543     0/imm32/no-disp32
20544     0/imm32/no-xm32
20545     0/imm32/no-x32
20546     0x11/imm32/alloc-id:fake
20547     _Primitive-loop-if->/imm32/next
20548 _Primitive-loop-if->:  # (payload primitive)
20549     0x11/imm32/alloc-id:fake:payload
20550     0x11/imm32/alloc-id:fake
20551     _string-loop-if->/imm32/name
20552     0/imm32/no-inouts
20553     0/imm32/no-inouts
20554     0/imm32/no-outputs
20555     0/imm32/no-outputs
20556     0x11/imm32/alloc-id:fake
20557     _string_0f_8f_jump_loop/imm32/subx-name
20558     0/imm32/no-rm32
20559     0/imm32/no-r32
20560     0/imm32/no-imm32
20561     0/imm32/no-imm8
20562     0/imm32/no-disp32
20563     0/imm32/no-xm32
20564     0/imm32/no-x32
20565     0x11/imm32/alloc-id:fake
20566     _Primitive-loop/imm32/next  # we probably don't need an unconditional break
20567 _Primitive-loop:  # (payload primitive)
20568     0x11/imm32/alloc-id:fake:payload
20569     0x11/imm32/alloc-id:fake
20570     _string-loop/imm32/name
20571     0/imm32/no-inouts
20572     0/imm32/no-inouts
20573     0/imm32/no-outputs
20574     0/imm32/no-outputs
20575     0x11/imm32/alloc-id:fake
20576     _string_e9_jump_loop/imm32/subx-name
20577     0/imm32/no-rm32
20578     0/imm32/no-r32
20579     0/imm32/no-imm32
20580     0/imm32/no-imm8
20581     0/imm32/no-disp32
20582     0/imm32/no-xm32
20583     0/imm32/no-x32
20584     0x11/imm32/alloc-id:fake
20585     _Primitive-break-if-addr<-named/imm32/next
20586 # - branches to named blocks
20587 _Primitive-break-if-addr<-named:  # (payload primitive)
20588     0x11/imm32/alloc-id:fake:payload
20589     0x11/imm32/alloc-id:fake
20590     _string-break-if-addr</imm32/name
20591     0x11/imm32/alloc-id:fake
20592     Single-lit-var/imm32/inouts
20593     0/imm32/no-outputs
20594     0/imm32/no-outputs
20595     0x11/imm32/alloc-id:fake
20596     _string_0f_82_jump_label/imm32/subx-name
20597     0/imm32/no-rm32
20598     0/imm32/no-r32
20599     0/imm32/no-imm32
20600     0/imm32/no-imm8
20601     1/imm32/disp32-is-first-inout
20602     0/imm32/no-xm32
20603     0/imm32/no-x32
20604     0x11/imm32/alloc-id:fake
20605     _Primitive-break-if-addr>=-named/imm32/next
20606 _Primitive-break-if-addr>=-named:  # (payload primitive)
20607     0x11/imm32/alloc-id:fake:payload
20608     0x11/imm32/alloc-id:fake
20609     _string-break-if-addr>=/imm32/name
20610     0x11/imm32/alloc-id:fake
20611     Single-lit-var/imm32/inouts
20612     0/imm32/no-outputs
20613     0/imm32/no-outputs
20614     0x11/imm32/alloc-id:fake
20615     _string_0f_83_jump_label/imm32/subx-name
20616     0/imm32/no-rm32
20617     0/imm32/no-r32
20618     0/imm32/no-imm32
20619     0/imm32/no-imm8
20620     1/imm32/disp32-is-first-inout
20621     0/imm32/no-xm32
20622     0/imm32/no-x32
20623     0x11/imm32/alloc-id:fake
20624     _Primitive-break-if-=-named/imm32/next
20625 _Primitive-break-if-=-named:  # (payload primitive)
20626     0x11/imm32/alloc-id:fake:payload
20627     0x11/imm32/alloc-id:fake
20628     _string-break-if-=/imm32/name
20629     0x11/imm32/alloc-id:fake
20630     Single-lit-var/imm32/inouts
20631     0/imm32/no-outputs
20632     0/imm32/no-outputs
20633     0x11/imm32/alloc-id:fake
20634     _string_0f_84_jump_label/imm32/subx-name
20635     0/imm32/no-rm32
20636     0/imm32/no-r32
20637     0/imm32/no-imm32
20638     0/imm32/no-imm8
20639     1/imm32/disp32-is-first-inout
20640     0/imm32/no-xm32
20641     0/imm32/no-x32
20642     0x11/imm32/alloc-id:fake
20643     _Primitive-break-if-!=-named/imm32/next
20644 _Primitive-break-if-!=-named:  # (payload primitive)
20645     0x11/imm32/alloc-id:fake:payload
20646     0x11/imm32/alloc-id:fake
20647     _string-break-if-!=/imm32/name
20648     0x11/imm32/alloc-id:fake
20649     Single-lit-var/imm32/inouts
20650     0/imm32/no-outputs
20651     0/imm32/no-outputs
20652     0x11/imm32/alloc-id:fake
20653     _string_0f_85_jump_label/imm32/subx-name
20654     0/imm32/no-rm32
20655     0/imm32/no-r32
20656     0/imm32/no-imm32
20657     0/imm32/no-imm8
20658     1/imm32/disp32-is-first-inout
20659     0/imm32/no-xm32
20660     0/imm32/no-x32
20661     0x11/imm32/alloc-id:fake
20662     _Primitive-break-if-addr<=-named/imm32/next
20663 _Primitive-break-if-addr<=-named:  # (payload primitive)
20664     0x11/imm32/alloc-id:fake:payload
20665     0x11/imm32/alloc-id:fake
20666     _string-break-if-addr<=/imm32/name
20667     0x11/imm32/alloc-id:fake
20668     Single-lit-var/imm32/inouts
20669     0/imm32/no-outputs
20670     0/imm32/no-outputs
20671     0x11/imm32/alloc-id:fake
20672     _string_0f_86_jump_label/imm32/subx-name
20673     0/imm32/no-rm32
20674     0/imm32/no-r32
20675     0/imm32/no-imm32
20676     0/imm32/no-imm8
20677     1/imm32/disp32-is-first-inout
20678     0/imm32/no-xm32
20679     0/imm32/no-x32
20680     0x11/imm32/alloc-id:fake
20681     _Primitive-break-if-addr>-named/imm32/next
20682 _Primitive-break-if-addr>-named:  # (payload primitive)
20683     0x11/imm32/alloc-id:fake:payload
20684     0x11/imm32/alloc-id:fake
20685     _string-break-if-addr>/imm32/name
20686     0x11/imm32/alloc-id:fake
20687     Single-lit-var/imm32/inouts
20688     0/imm32/no-outputs
20689     0/imm32/no-outputs
20690     0x11/imm32/alloc-id:fake
20691     _string_0f_87_jump_label/imm32/subx-name
20692     0/imm32/no-rm32
20693     0/imm32/no-r32
20694     0/imm32/no-imm32
20695     0/imm32/no-imm8
20696     1/imm32/disp32-is-first-inout
20697     0/imm32/no-xm32
20698     0/imm32/no-x32
20699     0x11/imm32/alloc-id:fake
20700     _Primitive-break-if-<-named/imm32/next
20701 _Primitive-break-if-<-named:  # (payload primitive)
20702     0x11/imm32/alloc-id:fake:payload
20703     0x11/imm32/alloc-id:fake
20704     _string-break-if-</imm32/name
20705     0x11/imm32/alloc-id:fake
20706     Single-lit-var/imm32/inouts
20707     0/imm32/no-outputs
20708     0/imm32/no-outputs
20709     0x11/imm32/alloc-id:fake
20710     _string_0f_8c_jump_label/imm32/subx-name
20711     0/imm32/no-rm32
20712     0/imm32/no-r32
20713     0/imm32/no-imm32
20714     0/imm32/no-imm8
20715     1/imm32/disp32-is-first-inout
20716     0/imm32/no-xm32
20717     0/imm32/no-x32
20718     0x11/imm32/alloc-id:fake
20719     _Primitive-break-if->=-named/imm32/next
20720 _Primitive-break-if->=-named:  # (payload primitive)
20721     0x11/imm32/alloc-id:fake:payload
20722     0x11/imm32/alloc-id:fake
20723     _string-break-if->=/imm32/name
20724     0x11/imm32/alloc-id:fake
20725     Single-lit-var/imm32/inouts
20726     0/imm32/no-outputs
20727     0/imm32/no-outputs
20728     0x11/imm32/alloc-id:fake
20729     _string_0f_8d_jump_label/imm32/subx-name
20730     0/imm32/no-rm32
20731     0/imm32/no-r32
20732     0/imm32/no-imm32
20733     0/imm32/no-imm8
20734     1/imm32/disp32-is-first-inout
20735     0/imm32/no-xm32
20736     0/imm32/no-x32
20737     0x11/imm32/alloc-id:fake
20738     _Primitive-break-if-<=-named/imm32/next
20739 _Primitive-break-if-<=-named:  # (payload primitive)
20740     0x11/imm32/alloc-id:fake:payload
20741     0x11/imm32/alloc-id:fake
20742     _string-break-if-<=/imm32/name
20743     0x11/imm32/alloc-id:fake
20744     Single-lit-var/imm32/inouts
20745     0/imm32/no-outputs
20746     0/imm32/no-outputs
20747     0x11/imm32/alloc-id:fake
20748     _string_0f_8e_jump_label/imm32/subx-name
20749     0/imm32/no-rm32
20750     0/imm32/no-r32
20751     0/imm32/no-imm32
20752     0/imm32/no-imm8
20753     1/imm32/disp32-is-first-inout
20754     0/imm32/no-xm32
20755     0/imm32/no-x32
20756     0x11/imm32/alloc-id:fake
20757     _Primitive-break-if->-named/imm32/next
20758 _Primitive-break-if->-named:  # (payload primitive)
20759     0x11/imm32/alloc-id:fake:payload
20760     0x11/imm32/alloc-id:fake
20761     _string-break-if->/imm32/name
20762     0x11/imm32/alloc-id:fake
20763     Single-lit-var/imm32/inouts
20764     0/imm32/no-outputs
20765     0/imm32/no-outputs
20766     0x11/imm32/alloc-id:fake
20767     _string_0f_8f_jump_label/imm32/subx-name
20768     0/imm32/no-rm32
20769     0/imm32/no-r32
20770     0/imm32/no-imm32
20771     0/imm32/no-imm8
20772     1/imm32/disp32-is-first-inout
20773     0/imm32/no-xm32
20774     0/imm32/no-x32
20775     0x11/imm32/alloc-id:fake
20776     _Primitive-break-named/imm32/next
20777 _Primitive-break-named:  # (payload primitive)
20778     0x11/imm32/alloc-id:fake:payload
20779     0x11/imm32/alloc-id:fake
20780     _string-break/imm32/name
20781     0x11/imm32/alloc-id:fake
20782     Single-lit-var/imm32/inouts
20783     0/imm32/no-outputs
20784     0/imm32/no-outputs
20785     0x11/imm32/alloc-id:fake
20786     _string_e9_jump_label/imm32/subx-name
20787     0/imm32/no-rm32
20788     0/imm32/no-r32
20789     0/imm32/no-imm32
20790     0/imm32/no-imm8
20791     1/imm32/disp32-is-first-inout
20792     0/imm32/no-xm32
20793     0/imm32/no-x32
20794     0x11/imm32/alloc-id:fake
20795     _Primitive-loop-if-addr<-named/imm32/next
20796 _Primitive-loop-if-addr<-named:  # (payload primitive)
20797     0x11/imm32/alloc-id:fake:payload
20798     0x11/imm32/alloc-id:fake
20799     _string-loop-if-addr</imm32/name
20800     0x11/imm32/alloc-id:fake
20801     Single-lit-var/imm32/inouts
20802     0/imm32/no-outputs
20803     0/imm32/no-outputs
20804     0x11/imm32/alloc-id:fake
20805     _string_0f_82_jump_label/imm32/subx-name
20806     0/imm32/no-rm32
20807     0/imm32/no-r32
20808     0/imm32/no-imm32
20809     0/imm32/no-imm8
20810     1/imm32/disp32-is-first-inout
20811     0/imm32/no-xm32
20812     0/imm32/no-x32
20813     0x11/imm32/alloc-id:fake
20814     _Primitive-loop-if-addr>=-named/imm32/next
20815 _Primitive-loop-if-addr>=-named:  # (payload primitive)
20816     0x11/imm32/alloc-id:fake:payload
20817     0x11/imm32/alloc-id:fake
20818     _string-loop-if-addr>=/imm32/name
20819     0x11/imm32/alloc-id:fake
20820     Single-lit-var/imm32/inouts
20821     0/imm32/no-outputs
20822     0/imm32/no-outputs
20823     0x11/imm32/alloc-id:fake
20824     _string_0f_83_jump_label/imm32/subx-name
20825     0/imm32/no-rm32
20826     0/imm32/no-r32
20827     0/imm32/no-imm32
20828     0/imm32/no-imm8
20829     1/imm32/disp32-is-first-inout
20830     0/imm32/no-xm32
20831     0/imm32/no-x32
20832     0x11/imm32/alloc-id:fake
20833     _Primitive-loop-if-=-named/imm32/next
20834 _Primitive-loop-if-=-named:  # (payload primitive)
20835     0x11/imm32/alloc-id:fake:payload
20836     0x11/imm32/alloc-id:fake
20837     _string-loop-if-=/imm32/name
20838     0x11/imm32/alloc-id:fake
20839     Single-lit-var/imm32/inouts
20840     0/imm32/no-outputs
20841     0/imm32/no-outputs
20842     0x11/imm32/alloc-id:fake
20843     _string_0f_84_jump_label/imm32/subx-name
20844     0/imm32/no-rm32
20845     0/imm32/no-r32
20846     0/imm32/no-imm32
20847     0/imm32/no-imm8
20848     1/imm32/disp32-is-first-inout
20849     0/imm32/no-xm32
20850     0/imm32/no-x32
20851     0x11/imm32/alloc-id:fake
20852     _Primitive-loop-if-!=-named/imm32/next
20853 _Primitive-loop-if-!=-named:  # (payload primitive)
20854     0x11/imm32/alloc-id:fake:payload
20855     0x11/imm32/alloc-id:fake
20856     _string-loop-if-!=/imm32/name
20857     0x11/imm32/alloc-id:fake
20858     Single-lit-var/imm32/inouts
20859     0/imm32/no-outputs
20860     0/imm32/no-outputs
20861     0x11/imm32/alloc-id:fake
20862     _string_0f_85_jump_label/imm32/subx-name
20863     0/imm32/no-rm32
20864     0/imm32/no-r32
20865     0/imm32/no-imm32
20866     0/imm32/no-imm8
20867     1/imm32/disp32-is-first-inout
20868     0/imm32/no-xm32
20869     0/imm32/no-x32
20870     0x11/imm32/alloc-id:fake
20871     _Primitive-loop-if-addr<=-named/imm32/next
20872 _Primitive-loop-if-addr<=-named:  # (payload primitive)
20873     0x11/imm32/alloc-id:fake:payload
20874     0x11/imm32/alloc-id:fake
20875     _string-loop-if-addr<=/imm32/name
20876     0x11/imm32/alloc-id:fake
20877     Single-lit-var/imm32/inouts
20878     0/imm32/no-outputs
20879     0/imm32/no-outputs
20880     0x11/imm32/alloc-id:fake
20881     _string_0f_86_jump_label/imm32/subx-name
20882     0/imm32/no-rm32
20883     0/imm32/no-r32
20884     0/imm32/no-imm32
20885     0/imm32/no-imm8
20886     1/imm32/disp32-is-first-inout
20887     0/imm32/no-xm32
20888     0/imm32/no-x32
20889     0x11/imm32/alloc-id:fake
20890     _Primitive-loop-if-addr>-named/imm32/next
20891 _Primitive-loop-if-addr>-named:  # (payload primitive)
20892     0x11/imm32/alloc-id:fake:payload
20893     0x11/imm32/alloc-id:fake
20894     _string-loop-if-addr>/imm32/name
20895     0x11/imm32/alloc-id:fake
20896     Single-lit-var/imm32/inouts
20897     0/imm32/no-outputs
20898     0/imm32/no-outputs
20899     0x11/imm32/alloc-id:fake
20900     _string_0f_87_jump_label/imm32/subx-name
20901     0/imm32/no-rm32
20902     0/imm32/no-r32
20903     0/imm32/no-imm32
20904     0/imm32/no-imm8
20905     1/imm32/disp32-is-first-inout
20906     0/imm32/no-xm32
20907     0/imm32/no-x32
20908     0x11/imm32/alloc-id:fake
20909     _Primitive-loop-if-<-named/imm32/next
20910 _Primitive-loop-if-<-named:  # (payload primitive)
20911     0x11/imm32/alloc-id:fake:payload
20912     0x11/imm32/alloc-id:fake
20913     _string-loop-if-</imm32/name
20914     0x11/imm32/alloc-id:fake
20915     Single-lit-var/imm32/inouts
20916     0/imm32/no-outputs
20917     0/imm32/no-outputs
20918     0x11/imm32/alloc-id:fake
20919     _string_0f_8c_jump_label/imm32/subx-name
20920     0/imm32/no-rm32
20921     0/imm32/no-r32
20922     0/imm32/no-imm32
20923     0/imm32/no-imm8
20924     1/imm32/disp32-is-first-inout
20925     0/imm32/no-xm32
20926     0/imm32/no-x32
20927     0x11/imm32/alloc-id:fake
20928     _Primitive-loop-if->=-named/imm32/next
20929 _Primitive-loop-if->=-named:  # (payload primitive)
20930     0x11/imm32/alloc-id:fake:payload
20931     0x11/imm32/alloc-id:fake
20932     _string-loop-if->=/imm32/name
20933     0x11/imm32/alloc-id:fake
20934     Single-lit-var/imm32/inouts
20935     0/imm32/no-outputs
20936     0/imm32/no-outputs
20937     0x11/imm32/alloc-id:fake
20938     _string_0f_8d_jump_label/imm32/subx-name
20939     0/imm32/no-rm32
20940     0/imm32/no-r32
20941     0/imm32/no-imm32
20942     0/imm32/no-imm8
20943     1/imm32/disp32-is-first-inout
20944     0/imm32/no-xm32
20945     0/imm32/no-x32
20946     0x11/imm32/alloc-id:fake
20947     _Primitive-loop-if-<=-named/imm32/next
20948 _Primitive-loop-if-<=-named:  # (payload primitive)
20949     0x11/imm32/alloc-id:fake:payload
20950     0x11/imm32/alloc-id:fake
20951     _string-loop-if-<=/imm32/name
20952     0x11/imm32/alloc-id:fake
20953     Single-lit-var/imm32/inouts
20954     0/imm32/no-outputs
20955     0/imm32/no-outputs
20956     0x11/imm32/alloc-id:fake
20957     _string_0f_8e_jump_label/imm32/subx-name
20958     0/imm32/no-rm32
20959     0/imm32/no-r32
20960     0/imm32/no-imm32
20961     0/imm32/no-imm8
20962     1/imm32/disp32-is-first-inout
20963     0/imm32/no-xm32
20964     0/imm32/no-x32
20965     0x11/imm32/alloc-id:fake
20966     _Primitive-loop-if->-named/imm32/next
20967 _Primitive-loop-if->-named:  # (payload primitive)
20968     0x11/imm32/alloc-id:fake:payload
20969     0x11/imm32/alloc-id:fake
20970     _string-loop-if->/imm32/name
20971     0x11/imm32/alloc-id:fake
20972     Single-lit-var/imm32/inouts
20973     0/imm32/no-outputs
20974     0/imm32/no-outputs
20975     0x11/imm32/alloc-id:fake
20976     _string_0f_8f_jump_label/imm32/subx-name
20977     0/imm32/no-rm32
20978     0/imm32/no-r32
20979     0/imm32/no-imm32
20980     0/imm32/no-imm8
20981     1/imm32/disp32-is-first-inout
20982     0/imm32/no-xm32
20983     0/imm32/no-x32
20984     0x11/imm32/alloc-id:fake
20985     _Primitive-loop-named/imm32/next  # we probably don't need an unconditional break
20986 _Primitive-loop-named:  # (payload primitive)
20987     0x11/imm32/alloc-id:fake:payload
20988     0x11/imm32/alloc-id:fake
20989     _string-loop/imm32/name
20990     0x11/imm32/alloc-id:fake
20991     Single-lit-var/imm32/inouts
20992     0/imm32/no-outputs
20993     0/imm32/no-outputs
20994     0x11/imm32/alloc-id:fake
20995     _string_e9_jump_label/imm32/subx-name
20996     0/imm32/no-rm32
20997     0/imm32/no-r32
20998     0/imm32/no-imm32
20999     0/imm32/no-imm8
21000     1/imm32/disp32-is-first-inout
21001     0/imm32/no-xm32
21002     0/imm32/no-x32
21003     0x11/imm32/alloc-id:fake
21004     _Primitive-break-if-float</imm32/next
21005 # - branches based on floating-point comparisons
21006 _Primitive-break-if-float<:  # (payload primitive)
21007     0x11/imm32/alloc-id:fake:payload
21008     0x11/imm32/alloc-id:fake
21009     _string-break-if-float</imm32/name
21010     0/imm32/no-inouts
21011     0/imm32/no-inouts
21012     0/imm32/no-outputs
21013     0/imm32/no-outputs
21014     0x11/imm32/alloc-id:fake
21015     _string_0f_82_jump_break/imm32/subx-name
21016     0/imm32/no-rm32
21017     0/imm32/no-r32
21018     0/imm32/no-imm32
21019     0/imm32/no-imm8
21020     0/imm32/no-disp32
21021     0/imm32/no-xm32
21022     0/imm32/no-x32
21023     0x11/imm32/alloc-id:fake
21024     _Primitive-break-if-float>=/imm32/next
21025 _Primitive-break-if-float>=:  # (payload primitive)
21026     0x11/imm32/alloc-id:fake:payload
21027     0x11/imm32/alloc-id:fake
21028     _string-break-if-float>=/imm32/name
21029     0/imm32/no-inouts
21030     0/imm32/no-inouts
21031     0/imm32/no-outputs
21032     0/imm32/no-outputs
21033     0x11/imm32/alloc-id:fake
21034     _string_0f_83_jump_break/imm32/subx-name
21035     0/imm32/no-rm32
21036     0/imm32/no-r32
21037     0/imm32/no-imm32
21038     0/imm32/no-imm8
21039     0/imm32/no-disp32
21040     0/imm32/no-xm32
21041     0/imm32/no-x32
21042     0x11/imm32/alloc-id:fake
21043     _Primitive-break-if-float<=/imm32/next
21044 _Primitive-break-if-float<=:  # (payload primitive)
21045     0x11/imm32/alloc-id:fake:payload
21046     0x11/imm32/alloc-id:fake
21047     _string-break-if-float<=/imm32/name
21048     0/imm32/no-inouts
21049     0/imm32/no-inouts
21050     0/imm32/no-outputs
21051     0/imm32/no-outputs
21052     0x11/imm32/alloc-id:fake
21053     _string_0f_86_jump_break/imm32/subx-name
21054     0/imm32/no-rm32
21055     0/imm32/no-r32
21056     0/imm32/no-imm32
21057     0/imm32/no-imm8
21058     0/imm32/no-disp32
21059     0/imm32/no-xm32
21060     0/imm32/no-x32
21061     0x11/imm32/alloc-id:fake
21062     _Primitive-break-if-float>/imm32/next
21063 _Primitive-break-if-float>:  # (payload primitive)
21064     0x11/imm32/alloc-id:fake:payload
21065     0x11/imm32/alloc-id:fake
21066     _string-break-if-float>/imm32/name
21067     0/imm32/no-inouts
21068     0/imm32/no-inouts
21069     0/imm32/no-outputs
21070     0/imm32/no-outputs
21071     0x11/imm32/alloc-id:fake
21072     _string_0f_87_jump_break/imm32/subx-name
21073     0/imm32/no-rm32
21074     0/imm32/no-r32
21075     0/imm32/no-imm32
21076     0/imm32/no-imm8
21077     0/imm32/no-disp32
21078     0/imm32/no-xm32
21079     0/imm32/no-x32
21080     0x11/imm32/alloc-id:fake
21081     _Primitive-loop-if-float</imm32/next
21082 _Primitive-loop-if-float<:  # (payload primitive)
21083     0x11/imm32/alloc-id:fake:payload
21084     0x11/imm32/alloc-id:fake
21085     _string-loop-if-float</imm32/name
21086     0/imm32/no-inouts
21087     0/imm32/no-inouts
21088     0/imm32/no-outputs
21089     0/imm32/no-outputs
21090     0x11/imm32/alloc-id:fake
21091     _string_0f_82_jump_loop/imm32/subx-name
21092     0/imm32/no-rm32
21093     0/imm32/no-r32
21094     0/imm32/no-imm32
21095     0/imm32/no-imm8
21096     0/imm32/no-disp32
21097     0/imm32/no-xm32
21098     0/imm32/no-x32
21099     0x11/imm32/alloc-id:fake
21100     _Primitive-loop-if-float>=/imm32/next
21101 _Primitive-loop-if-float>=:  # (payload primitive)
21102     0x11/imm32/alloc-id:fake:payload
21103     0x11/imm32/alloc-id:fake
21104     _string-loop-if-float>=/imm32/name
21105     0/imm32/no-inouts
21106     0/imm32/no-inouts
21107     0/imm32/no-outputs
21108     0/imm32/no-outputs
21109     0x11/imm32/alloc-id:fake
21110     _string_0f_83_jump_loop/imm32/subx-name
21111     0/imm32/no-rm32
21112     0/imm32/no-r32
21113     0/imm32/no-imm32
21114     0/imm32/no-imm8
21115     0/imm32/no-disp32
21116     0/imm32/no-xm32
21117     0/imm32/no-x32
21118     0x11/imm32/alloc-id:fake
21119     _Primitive-loop-if-float<=/imm32/next
21120 _Primitive-loop-if-float<=:  # (payload primitive)
21121     0x11/imm32/alloc-id:fake:payload
21122     0x11/imm32/alloc-id:fake
21123     _string-loop-if-float<=/imm32/name
21124     0/imm32/no-inouts
21125     0/imm32/no-inouts
21126     0/imm32/no-outputs
21127     0/imm32/no-outputs
21128     0x11/imm32/alloc-id:fake
21129     _string_0f_86_jump_loop/imm32/subx-name
21130     0/imm32/no-rm32
21131     0/imm32/no-r32
21132     0/imm32/no-imm32
21133     0/imm32/no-imm8
21134     0/imm32/no-disp32
21135     0/imm32/no-xm32
21136     0/imm32/no-x32
21137     0x11/imm32/alloc-id:fake
21138     _Primitive-loop-if-float>/imm32/next
21139 _Primitive-loop-if-float>:  # (payload primitive)
21140     0x11/imm32/alloc-id:fake:payload
21141     0x11/imm32/alloc-id:fake
21142     _string-loop-if-float>/imm32/name
21143     0/imm32/no-inouts
21144     0/imm32/no-inouts
21145     0/imm32/no-outputs
21146     0/imm32/no-outputs
21147     0x11/imm32/alloc-id:fake
21148     _string_0f_87_jump_loop/imm32/subx-name
21149     0/imm32/no-rm32
21150     0/imm32/no-r32
21151     0/imm32/no-imm32
21152     0/imm32/no-imm8
21153     0/imm32/no-disp32
21154     0/imm32/no-xm32
21155     0/imm32/no-x32
21156     0x11/imm32/alloc-id:fake
21157     _Primitive-break-if-float<-named/imm32/next
21158 _Primitive-break-if-float<-named:  # (payload primitive)
21159     0x11/imm32/alloc-id:fake:payload
21160     0x11/imm32/alloc-id:fake
21161     _string-break-if-float</imm32/name
21162     0x11/imm32/alloc-id:fake
21163     Single-lit-var/imm32/inouts
21164     0/imm32/no-outputs
21165     0/imm32/no-outputs
21166     0x11/imm32/alloc-id:fake
21167     _string_0f_82_jump_label/imm32/subx-name
21168     0/imm32/no-rm32
21169     0/imm32/no-r32
21170     0/imm32/no-imm32
21171     0/imm32/no-imm8
21172     1/imm32/disp32-is-first-inout
21173     0/imm32/no-xm32
21174     0/imm32/no-x32
21175     0x11/imm32/alloc-id:fake
21176     _Primitive-break-if-float>=-named/imm32/next
21177 _Primitive-break-if-float>=-named:  # (payload primitive)
21178     0x11/imm32/alloc-id:fake:payload
21179     0x11/imm32/alloc-id:fake
21180     _string-break-if-float>=/imm32/name
21181     0x11/imm32/alloc-id:fake
21182     Single-lit-var/imm32/inouts
21183     0/imm32/no-outputs
21184     0/imm32/no-outputs
21185     0x11/imm32/alloc-id:fake
21186     _string_0f_83_jump_label/imm32/subx-name
21187     0/imm32/no-rm32
21188     0/imm32/no-r32
21189     0/imm32/no-imm32
21190     0/imm32/no-imm8
21191     1/imm32/disp32-is-first-inout
21192     0/imm32/no-xm32
21193     0/imm32/no-x32
21194     0x11/imm32/alloc-id:fake
21195     _Primitive-break-if-float<=-named/imm32/next
21196 _Primitive-break-if-float<=-named:  # (payload primitive)
21197     0x11/imm32/alloc-id:fake:payload
21198     0x11/imm32/alloc-id:fake
21199     _string-break-if-float<=/imm32/name
21200     0x11/imm32/alloc-id:fake
21201     Single-lit-var/imm32/inouts
21202     0/imm32/no-outputs
21203     0/imm32/no-outputs
21204     0x11/imm32/alloc-id:fake
21205     _string_0f_86_jump_label/imm32/subx-name
21206     0/imm32/no-rm32
21207     0/imm32/no-r32
21208     0/imm32/no-imm32
21209     0/imm32/no-imm8
21210     1/imm32/disp32-is-first-inout
21211     0/imm32/no-xm32
21212     0/imm32/no-x32
21213     0x11/imm32/alloc-id:fake
21214     _Primitive-break-if-float>-named/imm32/next
21215 _Primitive-break-if-float>-named:  # (payload primitive)
21216     0x11/imm32/alloc-id:fake:payload
21217     0x11/imm32/alloc-id:fake
21218     _string-break-if-float>/imm32/name
21219     0x11/imm32/alloc-id:fake
21220     Single-lit-var/imm32/inouts
21221     0/imm32/no-outputs
21222     0/imm32/no-outputs
21223     0x11/imm32/alloc-id:fake
21224     _string_0f_87_jump_label/imm32/subx-name
21225     0/imm32/no-rm32
21226     0/imm32/no-r32
21227     0/imm32/no-imm32
21228     0/imm32/no-imm8
21229     1/imm32/disp32-is-first-inout
21230     0/imm32/no-xm32
21231     0/imm32/no-x32
21232     0x11/imm32/alloc-id:fake
21233     _Primitive-loop-if-float<-named/imm32/next
21234 _Primitive-loop-if-float<-named:  # (payload primitive)
21235     0x11/imm32/alloc-id:fake:payload
21236     0x11/imm32/alloc-id:fake
21237     _string-loop-if-float</imm32/name
21238     0x11/imm32/alloc-id:fake
21239     Single-lit-var/imm32/inouts
21240     0/imm32/no-outputs
21241     0/imm32/no-outputs
21242     0x11/imm32/alloc-id:fake
21243     _string_0f_82_jump_label/imm32/subx-name
21244     0/imm32/no-rm32
21245     0/imm32/no-r32
21246     0/imm32/no-imm32
21247     0/imm32/no-imm8
21248     1/imm32/disp32-is-first-inout
21249     0/imm32/no-xm32
21250     0/imm32/no-x32
21251     0x11/imm32/alloc-id:fake
21252     _Primitive-loop-if-float>=-named/imm32/next
21253 _Primitive-loop-if-float>=-named:  # (payload primitive)
21254     0x11/imm32/alloc-id:fake:payload
21255     0x11/imm32/alloc-id:fake
21256     _string-loop-if-float>=/imm32/name
21257     0x11/imm32/alloc-id:fake
21258     Single-lit-var/imm32/inouts
21259     0/imm32/no-outputs
21260     0/imm32/no-outputs
21261     0x11/imm32/alloc-id:fake
21262     _string_0f_83_jump_label/imm32/subx-name
21263     0/imm32/no-rm32
21264     0/imm32/no-r32
21265     0/imm32/no-imm32
21266     0/imm32/no-imm8
21267     1/imm32/disp32-is-first-inout
21268     0/imm32/no-xm32
21269     0/imm32/no-x32
21270     0x11/imm32/alloc-id:fake
21271     _Primitive-loop-if-float<=-named/imm32/next
21272 _Primitive-loop-if-float<=-named:  # (payload primitive)
21273     0x11/imm32/alloc-id:fake:payload
21274     0x11/imm32/alloc-id:fake
21275     _string-loop-if-float<=/imm32/name
21276     0x11/imm32/alloc-id:fake
21277     Single-lit-var/imm32/inouts
21278     0/imm32/no-outputs
21279     0/imm32/no-outputs
21280     0x11/imm32/alloc-id:fake
21281     _string_0f_86_jump_label/imm32/subx-name
21282     0/imm32/no-rm32
21283     0/imm32/no-r32
21284     0/imm32/no-imm32
21285     0/imm32/no-imm8
21286     1/imm32/disp32-is-first-inout
21287     0/imm32/no-xm32
21288     0/imm32/no-x32
21289     0x11/imm32/alloc-id:fake
21290     _Primitive-loop-if-float>-named/imm32/next
21291 _Primitive-loop-if-float>-named:  # (payload primitive)
21292     0x11/imm32/alloc-id:fake:payload
21293     0x11/imm32/alloc-id:fake
21294     _string-loop-if-float>/imm32/name
21295     0x11/imm32/alloc-id:fake
21296     Single-lit-var/imm32/inouts
21297     0/imm32/no-outputs
21298     0/imm32/no-outputs
21299     0x11/imm32/alloc-id:fake
21300     _string_0f_87_jump_label/imm32/subx-name
21301     0/imm32/no-rm32
21302     0/imm32/no-r32
21303     0/imm32/no-imm32
21304     0/imm32/no-imm8
21305     1/imm32/disp32-is-first-inout
21306     0/imm32/no-xm32
21307     0/imm32/no-x32
21308     0/imm32/next
21309     0/imm32/next
21310 
21311 # string literals for Mu instructions
21312 _string-add:  # (payload array byte)
21313     0x11/imm32/alloc-id:fake:payload
21314     # "add"
21315     0x3/imm32/size
21316     0x61/a 0x64/d 0x64/d
21317 _string-address:  # (payload array byte)
21318     0x11/imm32/alloc-id:fake:payload
21319     # "address"
21320     0x7/imm32/size
21321     0x61/a 0x64/d 0x64/d 0x72/r 0x65/e 0x73/s 0x73/s
21322 _string-add-to:  # (payload array byte)
21323     0x11/imm32/alloc-id:fake:payload
21324     # "add-to"
21325     0x6/imm32/size
21326     0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
21327 _string-and:  # (payload array byte)
21328     0x11/imm32/alloc-id:fake:payload
21329     # "and"
21330     0x3/imm32/size
21331     0x61/a 0x6e/n 0x64/d
21332 _string-and-with:  # (payload array byte)
21333     0x11/imm32/alloc-id:fake:payload
21334     # "and-with"
21335     0x8/imm32/size
21336     0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
21337 _string-break:  # (payload array byte)
21338     0x11/imm32/alloc-id:fake:payload
21339     # "break"
21340     0x5/imm32/size
21341     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k
21342 _string-break-if-<:  # (payload array byte)
21343     0x11/imm32/alloc-id:fake:payload
21344     # "break-if-<"
21345     0xa/imm32/size
21346     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
21347 _string-break-if-<=:  # (payload array byte)
21348     0x11/imm32/alloc-id:fake:payload
21349     # "break-if-<="
21350     0xb/imm32/size
21351     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
21352 _string-break-if-=:  # (payload array byte)
21353     0x11/imm32/alloc-id:fake:payload
21354     # "break-if-="
21355     0xa/imm32/size
21356     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
21357 _string-break-if->:  # (payload array byte)
21358     0x11/imm32/alloc-id:fake:payload
21359     # "break-if->"
21360     0xa/imm32/size
21361     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
21362 _string-break-if->=:  # (payload array byte)
21363     0x11/imm32/alloc-id:fake:payload
21364     # "break-if->="
21365     0xb/imm32/size
21366     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
21367 _string-break-if-!=:  # (payload array byte)
21368     0x11/imm32/alloc-id:fake:payload
21369     # "break-if-!="
21370     0xb/imm32/size
21371     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
21372 _string-break-if-addr<:  # (payload array byte)
21373     0x11/imm32/alloc-id:fake:payload
21374     # "break-if-addr<"
21375     0xe/imm32/size
21376     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/<
21377 _string-break-if-addr<=:  # (payload array byte)
21378     0x11/imm32/alloc-id:fake:payload
21379     # "break-if-addr<="
21380     0xf/imm32/size
21381     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/=
21382 _string-break-if-addr>:  # (payload array byte)
21383     0x11/imm32/alloc-id:fake:payload
21384     # "break-if-addr>"
21385     0xe/imm32/size
21386     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/>
21387 _string-break-if-addr>=:  # (payload array byte)
21388     0x11/imm32/alloc-id:fake:payload
21389     # "break-if-addr>="
21390     0xf/imm32/size
21391     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/=
21392 _string-break-if-float<:  # (payload array byte)
21393     0x11/imm32/alloc-id:fake:payload
21394     # "break-if-float<"
21395     0xf/imm32/size
21396     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x66/f 0x6c/l 0x6f/o 0x61/a 0x74/t 0x3c/<
21397 _string-break-if-float<=:  # (payload array byte)
21398     0x11/imm32/alloc-id:fake:payload
21399     # "break-if-float<="
21400     0x10/imm32/size
21401     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x66/f 0x6c/l 0x6f/o 0x61/a 0x74/t 0x3c/< 0x3d/=
21402 _string-break-if-float>:  # (payload array byte)
21403     0x11/imm32/alloc-id:fake:payload
21404     # "break-if-float>"
21405     0xf/imm32/size
21406     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x66/f 0x6c/l 0x6f/o 0x61/a 0x74/t 0x3e/>
21407 _string-break-if-float>=:  # (payload array byte)
21408     0x11/imm32/alloc-id:fake:payload
21409     # "break-if-float>="
21410     0x10/imm32/size
21411     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x66/f 0x6c/l 0x6f/o 0x61/a 0x74/t 0x3e/> 0x3d/=
21412 _string-compare:  # (payload array byte)
21413     0x11/imm32/alloc-id:fake:payload
21414     # "compare"
21415     0x7/imm32/size
21416     0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e
21417 _string-copy:  # (payload array byte)
21418     0x11/imm32/alloc-id:fake:payload
21419     # "copy"
21420     0x4/imm32/size
21421     0x63/c 0x6f/o 0x70/p 0x79/y
21422 _string-copy-to:  # (payload array byte)
21423     0x11/imm32/alloc-id:fake:payload
21424     # "copy-to"
21425     0x7/imm32/size
21426     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o
21427 _string-copy-byte:
21428     0x11/imm32/alloc-id:fake:payload
21429     # "copy-byte"
21430     0x9/imm32/size
21431     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e
21432 _string-copy-byte-to:
21433     0x11/imm32/alloc-id:fake:payload
21434     # "copy-byte-to"
21435     0xc/imm32/size
21436     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x74/t 0x6f/o
21437 _string-decrement:  # (payload array byte)
21438     0x11/imm32/alloc-id:fake:payload
21439     # "decrement"
21440     0x9/imm32/size
21441     0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
21442 _string-increment:  # (payload array byte)
21443     0x11/imm32/alloc-id:fake:payload
21444     # "increment"
21445     0x9/imm32/size
21446     0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
21447 _string-loop:  # (payload array byte)
21448     0x11/imm32/alloc-id:fake:payload
21449     # "loop"
21450     0x4/imm32/size
21451     0x6c/l 0x6f/o 0x6f/o 0x70/p
21452 _string-loop-if-<:  # (payload array byte)
21453     0x11/imm32/alloc-id:fake:payload
21454     # "loop-if-<"
21455     0x9/imm32/size
21456     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
21457 _string-loop-if-<=:  # (payload array byte)
21458     0x11/imm32/alloc-id:fake:payload
21459     # "loop-if-<="
21460     0xa/imm32/size
21461     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
21462 _string-loop-if-=:  # (payload array byte)
21463     0x11/imm32/alloc-id:fake:payload
21464     # "loop-if-="
21465     0x9/imm32/size
21466     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
21467 _string-loop-if->:  # (payload array byte)
21468     0x11/imm32/alloc-id:fake:payload
21469     # "loop-if->"
21470     0x9/imm32/size
21471     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
21472 _string-loop-if->=:  # (payload array byte)
21473     0x11/imm32/alloc-id:fake:payload
21474     # "loop-if->="
21475     0xa/imm32/size
21476     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
21477 _string-loop-if-!=:  # (payload array byte)
21478     0x11/imm32/alloc-id:fake:payload
21479     # "loop-if-!="
21480     0xa/imm32/size
21481     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
21482 _string-loop-if-addr<:  # (payload array byte)
21483     0x11/imm32/alloc-id:fake:payload
21484     # "loop-if-addr<"
21485     0xd/imm32/size
21486     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/<
21487 _string-loop-if-addr<=:  # (payload array byte)
21488     0x11/imm32/alloc-id:fake:payload
21489     # "loop-if-addr<="
21490     0xe/imm32/size
21491     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/=
21492 _string-loop-if-addr>:  # (payload array byte)
21493     0x11/imm32/alloc-id:fake:payload
21494     # "loop-if-addr>"
21495     0xd/imm32/size
21496     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/>
21497 _string-loop-if-addr>=:  # (payload array byte)
21498     0x11/imm32/alloc-id:fake:payload
21499     # "loop-if-addr>="
21500     0xe/imm32/size
21501     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/=
21502 _string-loop-if-float<:  # (payload array byte)
21503     0x11/imm32/alloc-id:fake:payload
21504     # "loop-if-float<"
21505     0xe/imm32/size
21506     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x66/f 0x6c/l 0x6f/o 0x61/a 0x74/t 0x3c/<
21507 _string-loop-if-float<=:  # (payload array byte)
21508     0x11/imm32/alloc-id:fake:payload
21509     # "loop-if-float<="
21510     0xf/imm32/size
21511     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x66/f 0x6c/l 0x6f/o 0x61/a 0x74/t 0x3c/< 0x3d/=
21512 _string-loop-if-float>:  # (payload array byte)
21513     0x11/imm32/alloc-id:fake:payload
21514     # "loop-if-float>"
21515     0xe/imm32/size
21516     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x66/f 0x6c/l 0x6f/o 0x61/a 0x74/t 0x3e/>
21517 _string-loop-if-float>=:  # (payload array byte)
21518     0x11/imm32/alloc-id:fake:payload
21519     # "loop-if-float>="
21520     0xf/imm32/size
21521     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x66/f 0x6c/l 0x6f/o 0x61/a 0x74/t 0x3e/> 0x3d/=
21522 _string-multiply:  # (payload array byte)
21523     0x11/imm32/alloc-id:fake:payload
21524     # "multiply"
21525     0x8/imm32/size
21526     0x6d/m 0x75/u 0x6c/l 0x74/t 0x69/i 0x70/p 0x6c/l 0x79/y
21527 _string-convert:  # (payload array byte)
21528     0x11/imm32/alloc-id:fake:payload
21529     # "convert"
21530     0x7/imm32/size
21531     0x63/c 0x6f/o 0x6e/n 0x76/v 0x65/e 0x72/r 0x74/t
21532 _string-divide:
21533     0x11/imm32/alloc-id:fake:payload
21534     # "divide"
21535     0x6/imm32/size
21536     0x64/d 0x69/i 0x76/v 0x69/i 0x64/d 0x65/e
21537 _string-max:
21538     0x11/imm32/alloc-id:fake:payload
21539     # "max"
21540     0x3/imm32/size
21541     0x6d/m 0x61/a 0x78/x
21542 _string-min:
21543     0x11/imm32/alloc-id:fake:payload
21544     # "min"
21545     0x3/imm32/size
21546     0x6d/m 0x69/i 0x6e/n
21547 _string-reciprocal:
21548     0x11/imm32/alloc-id:fake:payload
21549     # "reciprocal"
21550     0xa/imm32/size
21551     0x72/r 0x65/e 0x63/c 0x69/i 0x70/p 0x72/r 0x6f/o 0x63/c 0x61/a 0x6c/l
21552 _string-square-root:
21553     0x11/imm32/alloc-id:fake:payload
21554     # "square-root"
21555     0xb/imm32/size
21556     0x73/s 0x71/q 0x75/u 0x61/a 0x72/r 0x65/e 0x2d/- 0x72/r 0x6f/o 0x6f/o 0x74/t
21557 _string-inverse-square-root:
21558     0x11/imm32/alloc-id:fake:payload
21559     # "inverse-square-root"
21560     0x13/imm32/size
21561     0x69/i 0x6e/n 0x76/v 0x65/e 0x72/r 0x73/s 0x65/e 0x2d/- 0x73/s 0x71/q 0x75/u 0x61/a 0x72/r 0x65/e 0x2d/- 0x72/r 0x6f/o 0x6f/o 0x74/t
21562 _string-negate:  # (payload array byte)
21563     0x11/imm32/alloc-id:fake:payload
21564     # "negate"
21565     0x6/imm32/size
21566     0x6e/n 0x65/e 0x67/g 0x61/a 0x74/t 0x65/e
21567 _string-or:  # (payload array byte)
21568     0x11/imm32/alloc-id:fake:payload
21569     # "or"
21570     0x2/imm32/size
21571     0x6f/o 0x72/r
21572 _string-or-with:  # (payload array byte)
21573     0x11/imm32/alloc-id:fake:payload
21574     # "or-with"
21575     0x7/imm32/size
21576     0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
21577 _string-subtract:  # (payload array byte)
21578     0x11/imm32/alloc-id:fake:payload
21579     # "subtract"
21580     0x8/imm32/size
21581     0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
21582 _string-subtract-from:  # (payload array byte)
21583     0x11/imm32/alloc-id:fake:payload
21584     # "subtract-from"
21585     0xd/imm32/size
21586     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
21587 _string-xor:  # (payload array byte)
21588     0x11/imm32/alloc-id:fake:payload
21589     # "xor"
21590     0x3/imm32/size
21591     0x78/x 0x6f/o 0x72/r
21592 _string-xor-with:  # (payload array byte)
21593     0x11/imm32/alloc-id:fake:payload
21594     # "xor-with"
21595     0x8/imm32/size
21596     0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
21597 _string-shift-left:  # (payload array byte)
21598     0x11/imm32/alloc-id:fake:payload
21599     # "shift-left"
21600     0xa/imm32/size
21601     0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x2d/dash 0x6c/l 0x65/e 0x66/f 0x74/t
21602 _string-shift-right:  # (payload array byte)
21603     0x11/imm32/alloc-id:fake:payload
21604     # "shift-right"
21605     0xb/imm32/size
21606     0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x2d/dash 0x72/r 0x69/i 0x67/g 0x68/h 0x74/t
21607 _string-shift-right-signed:  # (payload array byte)
21608     0x11/imm32/alloc-id:fake:payload
21609     # "shift-right-signed"
21610     0x12/imm32/size
21611     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
21612 
21613 # string literals for SubX instructions
21614 _string_01_add_to:  # (payload array byte)
21615     0x11/imm32/alloc-id:fake:payload
21616     # "01/add-to"
21617     0x9/imm32/size
21618     0x30/0 0x31/1 0x2f/slash 0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
21619 _string_03_add:  # (payload array byte)
21620     0x11/imm32/alloc-id:fake:payload
21621     # "03/add"
21622     0x6/imm32/size
21623     0x30/0 0x33/3 0x2f/slash 0x61/a 0x64/d 0x64/d
21624 _string_05_add_to_eax:  # (payload array byte)
21625     0x11/imm32/alloc-id:fake:payload
21626     # "05/add-to-eax"
21627     0xd/imm32/size
21628     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
21629 _string_09_or_with:  # (payload array byte)
21630     0x11/imm32/alloc-id:fake:payload
21631     # "09/or-with"
21632     0xa/imm32/size
21633     0x30/0 0x39/9 0x2f/slash 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
21634 _string_0b_or:  # (payload array byte)
21635     0x11/imm32/alloc-id:fake:payload
21636     # "0b/or"
21637     0x5/imm32/size
21638     0x30/0 0x62/b 0x2f/slash 0x6f/o 0x72/r
21639 _string_0d_or_with_eax:  # (payload array byte)
21640     0x11/imm32/alloc-id:fake:payload
21641     # "0d/or-with-eax"
21642     0xe/imm32/size
21643     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
21644 _string_0f_82_jump_label:  # (payload array byte)
21645     0x11/imm32/alloc-id:fake:payload
21646     # "0f 82/jump-if-addr<"
21647     0x13/imm32/size
21648     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/<
21649 _string_0f_82_jump_break:  # (payload array byte)
21650     0x11/imm32/alloc-id:fake:payload
21651     # "0f 82/jump-if-addr< break/disp32"
21652     0x20/imm32/size
21653     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
21654 _string_0f_82_jump_loop:  # (payload array byte)
21655     0x11/imm32/alloc-id:fake:payload
21656     # "0f 82/jump-if-addr< loop/disp32"
21657     0x1f/imm32/size
21658     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
21659 _string_0f_83_jump_label:  # (payload array byte)
21660     0x11/imm32/alloc-id:fake:payload
21661     # "0f 83/jump-if-addr>="
21662     0x14/imm32/size
21663     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/=
21664 _string_0f_83_jump_break:  # (payload array byte)
21665     0x11/imm32/alloc-id:fake:payload
21666     # "0f 83/jump-if-addr>= break/disp32"
21667     0x21/imm32/size
21668     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
21669 _string_0f_83_jump_loop:  # (payload array byte)
21670     0x11/imm32/alloc-id:fake:payload
21671     # "0f 83/jump-if-addr>= loop/disp32"
21672     0x20/imm32/size
21673     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
21674 _string_0f_84_jump_label:  # (payload array byte)
21675     0x11/imm32/alloc-id:fake:payload
21676     # "0f 84/jump-if-="
21677     0xf/imm32/size
21678     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/=
21679 _string_0f_84_jump_break:  # (payload array byte)
21680     0x11/imm32/alloc-id:fake:payload
21681     # "0f 84/jump-if-= break/disp32"
21682     0x1c/imm32/size
21683     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
21684 _string_0f_84_jump_loop:  # (payload array byte)
21685     0x11/imm32/alloc-id:fake:payload
21686     # "0f 84/jump-if-= loop/disp32"
21687     0x1b/imm32/size
21688     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
21689 _string_0f_85_jump_label:  # (payload array byte)
21690     0x11/imm32/alloc-id:fake:payload
21691     # "0f 85/jump-if-!="
21692     0x10/imm32/size
21693     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/=
21694 _string_0f_85_jump_break:  # (payload array byte)
21695     0x11/imm32/alloc-id:fake:payload
21696     # "0f 85/jump-if-!= break/disp32"
21697     0x1d/imm32/size
21698     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
21699 _string_0f_85_jump_loop:  # (payload array byte)
21700     0x11/imm32/alloc-id:fake:payload
21701     # "0f 85/jump-if-!= loop/disp32"
21702     0x1c/imm32/size
21703     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
21704 _string_0f_86_jump_label:  # (payload array byte)
21705     0x11/imm32/alloc-id:fake:payload
21706     # "0f 86/jump-if-addr<="
21707     0x14/imm32/size
21708     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/=
21709 _string_0f_86_jump_break:  # (payload array byte)
21710     0x11/imm32/alloc-id:fake:payload
21711     # "0f 86/jump-if-addr<= break/disp32"
21712     0x21/imm32/size
21713     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
21714 _string_0f_86_jump_loop:  # (payload array byte)
21715     0x11/imm32/alloc-id:fake:payload
21716     # "0f 86/jump-if-addr<= loop/disp32"
21717     0x20/imm32/size
21718     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
21719 _string_0f_87_jump_label:  # (payload array byte)
21720     0x11/imm32/alloc-id:fake:payload
21721     # "0f 87/jump-if-addr>"
21722     0x13/imm32/size
21723     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/>
21724 _string_0f_87_jump_break:  # (payload array byte)
21725     0x11/imm32/alloc-id:fake:payload
21726     # "0f 87/jump-if-addr> break/disp32"
21727     0x20/imm32/size
21728     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
21729 _string_0f_87_jump_loop:  # (payload array byte)
21730     0x11/imm32/alloc-id:fake:payload
21731     # "0f 87/jump-if-addr> loop/disp32"
21732     0x1f/imm32/size
21733     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
21734 _string_0f_8c_jump_label:  # (payload array byte)
21735     0x11/imm32/alloc-id:fake:payload
21736     # "0f 8c/jump-if-<"
21737     0xf/imm32/size
21738     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/<
21739 _string_0f_8c_jump_break:  # (payload array byte)
21740     0x11/imm32/alloc-id:fake:payload
21741     # "0f 8c/jump-if-< break/disp32"
21742     0x1c/imm32/size
21743     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
21744 _string_0f_8c_jump_loop:  # (payload array byte)
21745     0x11/imm32/alloc-id:fake:payload
21746     # "0f 8c/jump-if-< loop/disp32"
21747     0x1b/imm32/size
21748     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
21749 _string_0f_8d_jump_label:  # (payload array byte)
21750     0x11/imm32/alloc-id:fake:payload
21751     # "0f 8d/jump-if->="
21752     0x10/imm32/size
21753     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/=
21754 _string_0f_8d_jump_break:  # (payload array byte)
21755     0x11/imm32/alloc-id:fake:payload
21756     # "0f 8d/jump-if->= break/disp32"
21757     0x1d/imm32/size
21758     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
21759 _string_0f_8d_jump_loop:  # (payload array byte)
21760     0x11/imm32/alloc-id:fake:payload
21761     # "0f 8d/jump-if->= loop/disp32"
21762     0x1c/imm32/size
21763     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
21764 _string_0f_8e_jump_label:  # (payload array byte)
21765     0x11/imm32/alloc-id:fake:payload
21766     # "0f 8e/jump-if-<="
21767     0x10/imm32/size
21768     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/=
21769 _string_0f_8e_jump_break:  # (payload array byte)
21770     0x11/imm32/alloc-id:fake:payload
21771     # "0f 8e/jump-if-<= break/disp32"
21772     0x1d/imm32/size
21773     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
21774 _string_0f_8e_jump_loop:  # (payload array byte)
21775     0x11/imm32/alloc-id:fake:payload
21776     # "0f 8e/jump-if-<= loop/disp32"
21777     0x1c/imm32/size
21778     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
21779 _string_0f_8f_jump_label:  # (payload array byte)
21780     0x11/imm32/alloc-id:fake:payload
21781     # "0f 8f/jump-if->"
21782     0xf/imm32/size
21783     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/>
21784 _string_0f_8f_jump_break:  # (payload array byte)
21785     0x11/imm32/alloc-id:fake:payload
21786     # "0f 8f/jump-if-> break/disp32"
21787     0x1c/imm32/size
21788     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
21789 _string_0f_8f_jump_loop:  # (payload array byte)
21790     0x11/imm32/alloc-id:fake:payload
21791     # "0f 8f/jump-if-> loop/disp32"
21792     0x1b/imm32/size
21793     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
21794 _string_0f_af_multiply:  # (payload array byte)
21795     0x11/imm32/alloc-id:fake:payload
21796     # "0f af/multiply"
21797     0xe/imm32/size
21798     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
21799 _string_f3_0f_2a_convert_to_float:
21800     0x11/imm32/alloc-id:fake:payload
21801     # "f3 0f 2a/convert-to-float"
21802     0x19/imm32/size
21803     0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x32/2 0x61/a 0x2f/slash 0x63/c 0x6f/o 0x6e/n 0x76/v 0x65/e 0x72/r 0x74/t 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x66/f 0x6c/l 0x6f/o 0x61/a 0x74/t
21804 _string_f3_0f_2d_convert_to_int:
21805     0x11/imm32/alloc-id:fake:payload
21806     # "f3 0f 2d/convert-to-int"
21807     0x17/imm32/size
21808     0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x32/2 0x64/d 0x2f/slash 0x63/c 0x6f/o 0x6e/n 0x76/v 0x65/e 0x72/r 0x74/t 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x69/i 0x6e/n 0x74/t
21809 _string_f3_0f_58_add:
21810     0x11/imm32/alloc-id:fake:payload
21811     # "f3 0f 58/add"
21812     0xc/imm32/size
21813     0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x35/5 0x38/8 0x2f/slash 0x61/a 0x64/d 0x64/d
21814 _string_f3_0f_5c_subtract:
21815     0x11/imm32/alloc-id:fake:payload
21816     # "f3 0f 5c/subtract"
21817     0x11/imm32/size
21818     0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x35/5 0x63/c 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
21819 _string_f3_0f_59_multiply:
21820     0x11/imm32/alloc-id:fake:payload
21821     # "f3 0f 59/multiply"
21822     0x11/imm32/size
21823     0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x35/5 0x39/9 0x2f/slash 0x6d/m 0x75/u 0x6c/l 0x74/t 0x69/i 0x70/p 0x6c/l 0x79/y
21824 _string_f3_0f_5e_divide:
21825     0x11/imm32/alloc-id:fake:payload
21826     # "f3 0f 5e/divide"
21827     0xf/imm32/size
21828     0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x35/5 0x65/e 0x2f/slash 0x64/d 0x69/i 0x76/v 0x69/i 0x64/d 0x65/e
21829 _string_f3_0f_53_reciprocal:
21830     0x11/imm32/alloc-id:fake:payload
21831     # "f3 0f 53/reciprocal"
21832     0x13/imm32/size
21833     0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x35/5 0x33/3 0x2f/slash 0x72/r 0x65/e 0x63/c 0x69/i 0x70/p 0x72/r 0x6f/o 0x63/c 0x61/a 0x6c/l
21834 _string_f3_0f_51_square_root:
21835     0x11/imm32/alloc-id:fake:payload
21836     # "f3 0f 51/square-root"
21837     0x14/imm32/size
21838     0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x35/5 0x31/1 0x2f/slash 0x73/s 0x71/q 0x75/u 0x61/a 0x72/r 0x65/e 0x2d/dash 0x72/r 0x6f/o 0x6f/o 0x74/t
21839 _string_f3_0f_52_inverse_square_root:
21840     0x11/imm32/alloc-id:fake:payload
21841     # "f3 0f 52/inverse-square-root"
21842     0x1c/imm32/size
21843     0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x35/5 0x32/2 0x2f/slash 0x69/i 0x6e/n 0x76/v 0x65/e 0x72/r 0x73/s 0x65/e 0x2d/dash 0x73/s 0x71/q 0x75/u 0x61/a 0x72/r 0x65/e 0x2d/dash 0x72/r 0x6f/o 0x6f/o 0x74/t
21844 _string_f3_0f_5d_min:
21845     0x11/imm32/alloc-id:fake:payload
21846     # "f3 0f 5d/min"
21847     0xc/imm32/size
21848     0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x35/5 0x64/d 0x2f/slash 0x6d/m 0x69/i 0x6e/n
21849 _string_f3_0f_5f_max:
21850     0x11/imm32/alloc-id:fake:payload
21851     # "f3 0f 5f/max"
21852     0xc/imm32/size
21853     0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x35/5 0x66/f 0x2f/slash 0x6d/m 0x61/a 0x78/x
21854 _string_f3_0f_10_copy:
21855     0x11/imm32/alloc-id:fake:payload
21856     # "f3 0f 10/copy"
21857     0xd/imm32/size
21858     0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x31/1 0x30/0 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y
21859 _string_f3_0f_11_copy:
21860     0x11/imm32/alloc-id:fake:payload
21861     # "f3 0f 11/copy"
21862     0xd/imm32/size
21863     0x66/f 0x33/3 0x20/space 0x30/0 0x66/f 0x20/space 0x31/1 0x31/1 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y
21864 _string_0f_2f_compare:
21865     0x11/imm32/alloc-id:fake:payload
21866     # "0f 2f/compare"
21867     0xd/imm32/size
21868     0x30/0 0x66/f 0x20/space 0x32/2 0x66/f 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e
21869 _string_21_and_with:  # (payload array byte)
21870     0x11/imm32/alloc-id:fake:payload
21871     # "21/and-with"
21872     0xb/imm32/size
21873     0x32/2 0x31/1 0x2f/slash 0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
21874 _string_23_and:  # (payload array byte)
21875     0x11/imm32/alloc-id:fake:payload
21876     # "23/and"
21877     0x6/imm32/size
21878     0x32/2 0x33/3 0x2f/slash 0x61/a 0x6e/n 0x64/d
21879 _string_25_and_with_eax:  # (payload array byte)
21880     0x11/imm32/alloc-id:fake:payload
21881     # "25/and-with-eax"
21882     0xf/imm32/size
21883     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
21884 _string_29_subtract_from:  # (payload array byte)
21885     0x11/imm32/alloc-id:fake:payload
21886     # "29/subtract-from"
21887     0x10/imm32/size
21888     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
21889 _string_2b_subtract:  # (payload array byte)
21890     0x11/imm32/alloc-id:fake:payload
21891     # "2b/subtract"
21892     0xb/imm32/size
21893     0x32/2 0x62/b 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
21894 _string_2d_subtract_from_eax:  # (payload array byte)
21895     0x11/imm32/alloc-id:fake:payload
21896     # "2d/subtract-from-eax"
21897     0x14/imm32/size
21898     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
21899 _string_31_xor_with:  # (payload array byte)
21900     0x11/imm32/alloc-id:fake:payload
21901     # "31/xor-with"
21902     0xb/imm32/size
21903     0x33/3 0x31/1 0x2f/slash 0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
21904 _string_33_xor:  # (payload array byte)
21905     0x11/imm32/alloc-id:fake:payload
21906     # "33/xor"
21907     0x6/imm32/size
21908     0x33/3 0x33/3 0x2f/slash 0x78/x 0x6f/o 0x72/r
21909 _string_35_xor_with_eax:  # (payload array byte)
21910     0x11/imm32/alloc-id:fake:payload
21911     # "35/xor-with-eax"
21912     0xf/imm32/size
21913     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
21914 _string_39_compare->:  # (payload array byte)
21915     0x11/imm32/alloc-id:fake:payload
21916     # "39/compare->"
21917     0xc/imm32/size
21918     0x33/3 0x39/9 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x2d/dash 0x3e/>
21919 _string_3b_compare<-:  # (payload array byte)
21920     0x11/imm32/alloc-id:fake:payload
21921     # "3b/compare<-"
21922     0xc/imm32/size
21923     0x33/3 0x62/b 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x3c/< 0x2d/dash
21924 _string_3d_compare_eax_with:  # (payload array byte)
21925     0x11/imm32/alloc-id:fake:payload
21926     # "3d/compare-eax-with"
21927     0x13/imm32/size
21928     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
21929 _string_40_increment_eax:  # (payload array byte)
21930     0x11/imm32/alloc-id:fake:payload
21931     # "40/increment-eax"
21932     0x10/imm32/size
21933     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
21934 _string_41_increment_ecx:  # (payload array byte)
21935     0x11/imm32/alloc-id:fake:payload
21936     # "41/increment-ecx"
21937     0x10/imm32/size
21938     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
21939 _string_42_increment_edx:  # (payload array byte)
21940     0x11/imm32/alloc-id:fake:payload
21941     # "42/increment-edx"
21942     0x10/imm32/size
21943     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
21944 _string_43_increment_ebx:  # (payload array byte)
21945     0x11/imm32/alloc-id:fake:payload
21946     # "43/increment-ebx"
21947     0x10/imm32/size
21948     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
21949 _string_46_increment_esi:  # (payload array byte)
21950     0x11/imm32/alloc-id:fake:payload
21951     # "46/increment-esi"
21952     0x10/imm32/size
21953     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
21954 _string_47_increment_edi:  # (payload array byte)
21955     0x11/imm32/alloc-id:fake:payload
21956     # "47/increment-edi"
21957     0x10/imm32/size
21958     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
21959 _string_48_decrement_eax:  # (payload array byte)
21960     0x11/imm32/alloc-id:fake:payload
21961     # "48/decrement-eax"
21962     0x10/imm32/size
21963     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
21964 _string_49_decrement_ecx:  # (payload array byte)
21965     0x11/imm32/alloc-id:fake:payload
21966     # "49/decrement-ecx"
21967     0x10/imm32/size
21968     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
21969 _string_4a_decrement_edx:  # (payload array byte)
21970     0x11/imm32/alloc-id:fake:payload
21971     # "4a/decrement-edx"
21972     0x10/imm32/size
21973     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
21974 _string_4b_decrement_ebx:  # (payload array byte)
21975     0x11/imm32/alloc-id:fake:payload
21976     # "4b/decrement-ebx"
21977     0x10/imm32/size
21978     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
21979 _string_4e_decrement_esi:  # (payload array byte)
21980     0x11/imm32/alloc-id:fake:payload
21981     # "4e/decrement-esi"
21982     0x10/imm32/size
21983     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
21984 _string_4f_decrement_edi:  # (payload array byte)
21985     0x11/imm32/alloc-id:fake:payload
21986     # "4f/decrement-edi"
21987     0x10/imm32/size
21988     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
21989 _string_81_subop_add:  # (payload array byte)
21990     0x11/imm32/alloc-id:fake:payload
21991     # "81 0/subop/add"
21992     0xe/imm32/size
21993     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
21994 _string_81_subop_or:  # (payload array byte)
21995     0x11/imm32/alloc-id:fake:payload
21996     # "81 1/subop/or"
21997     0xd/imm32/size
21998     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
21999 _string_81_subop_and:  # (payload array byte)
22000     0x11/imm32/alloc-id:fake:payload
22001     # "81 4/subop/and"
22002     0xe/imm32/size
22003     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
22004 _string_81_subop_subtract:  # (payload array byte)
22005     0x11/imm32/alloc-id:fake:payload
22006     # "81 5/subop/subtract"
22007     0x13/imm32/size
22008     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
22009 _string_81_subop_xor:  # (payload array byte)
22010     0x11/imm32/alloc-id:fake:payload
22011     # "81 6/subop/xor"
22012     0xe/imm32/size
22013     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
22014 _string_81_subop_compare:  # (payload array byte)
22015     0x11/imm32/alloc-id:fake:payload
22016     # "81 7/subop/compare"
22017     0x12/imm32/size
22018     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
22019 _string_89_<-:  # (payload array byte)
22020     0x11/imm32/alloc-id:fake:payload
22021     # "89/<-"
22022     0x5/imm32/size
22023     0x38/8 0x39/9 0x2f/slash 0x3c/< 0x2d/dash
22024 _string_8b_->:  # (payload array byte)
22025     0x11/imm32/alloc-id:fake:payload
22026     # "8b/->"
22027     0x5/imm32/size
22028     0x38/8 0x62/b 0x2f/slash 0x2d/dash 0x3e/>
22029 _string_8a_copy_byte:
22030     0x11/imm32/alloc-id:fake:payload
22031     # "8a/byte->"
22032     0x9/imm32/size
22033     0x38/8 0x61/a 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x3e/>
22034 _string_88_copy_byte:
22035     0x11/imm32/alloc-id:fake:payload
22036     # "88/byte<-"
22037     0x9/imm32/size
22038     0x38/8 0x38/8 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x3c/< 0x2d/-
22039 _string_8d_copy_address:  # (payload array byte)
22040     0x11/imm32/alloc-id:fake:payload
22041     # "8d/copy-address"
22042     0xf/imm32/size
22043     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
22044 _string_b8_copy_to_eax:  # (payload array byte)
22045     0x11/imm32/alloc-id:fake:payload
22046     # "b8/copy-to-eax"
22047     0xe/imm32/size
22048     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
22049 _string_b9_copy_to_ecx:  # (payload array byte)
22050     0x11/imm32/alloc-id:fake:payload
22051     # "b9/copy-to-ecx"
22052     0xe/imm32/size
22053     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
22054 _string_ba_copy_to_edx:  # (payload array byte)
22055     0x11/imm32/alloc-id:fake:payload
22056     # "ba/copy-to-edx"
22057     0xe/imm32/size
22058     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
22059 _string_bb_copy_to_ebx:  # (payload array byte)
22060     0x11/imm32/alloc-id:fake:payload
22061     # "bb/copy-to-ebx"
22062     0xe/imm32/size
22063     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
22064 _string_be_copy_to_esi:  # (payload array byte)
22065     0x11/imm32/alloc-id:fake:payload
22066     # "be/copy-to-esi"
22067     0xe/imm32/size
22068     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
22069 _string_bf_copy_to_edi:  # (payload array byte)
22070     0x11/imm32/alloc-id:fake:payload
22071     # "bf/copy-to-edi"
22072     0xe/imm32/size
22073     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
22074 _string_c7_subop_copy:  # (payload array byte)
22075     0x11/imm32/alloc-id:fake:payload
22076     # "c7 0/subop/copy"
22077     0xf/imm32/size
22078     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
22079 _string_e9_jump_label:  # (payload array byte)
22080     0x11/imm32/alloc-id:fake:payload
22081     # "e9/jump"
22082     0x7/imm32/size
22083     0x65/e 0x39/9 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p
22084 _string_e9_jump_break:  # (payload array byte)
22085     0x11/imm32/alloc-id:fake:payload
22086     # "e9/jump break/disp32"
22087     0x14/imm32/size
22088     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
22089 _string_e9_jump_loop:  # (payload array byte)
22090     0x11/imm32/alloc-id:fake:payload
22091     # "e9/jump loop/disp32"
22092     0x13/imm32/size
22093     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
22094 _string_f7_subop_negate:
22095     0x11/imm32/alloc-id:fake:payload
22096     # "f7 3/subop/negate"
22097     0x11/imm32/size
22098     0x66/f 0x37/7 0x20/space 0x33/3 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x6e/n 0x65/e 0x67/g 0x61/a 0x74/t 0x65/e
22099 _string_ff_subop_increment:  # (payload array byte)
22100     0x11/imm32/alloc-id:fake:payload
22101     # "ff 0/subop/increment"
22102     0x14/imm32/size
22103     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
22104 _string_ff_subop_decrement:  # (payload array byte)
22105     0x11/imm32/alloc-id:fake:payload
22106     # "ff 1/subop/decrement"
22107     0x14/imm32/size
22108     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
22109 _string_c1_subop_shift_left:  # (payload array byte)
22110     0x11/imm32/alloc-id:fake:payload
22111     # "c1/shift 4/subop/left"
22112     0x15/imm32/size
22113     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
22114 _string_c1_subop_shift_right_padding_zeroes:  # (payload array byte)
22115     0x11/imm32/alloc-id:fake:payload
22116     # "c1/shift 5/subop/right-padding-zeroes"
22117     0x25/imm32/size
22118     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
22119 _string_c1_subop_shift_right_preserving_sign:  # (payload array byte)
22120     0x11/imm32/alloc-id:fake:payload
22121     # "c1/shift 7/subop/right-preserving-sign"
22122     0x26/imm32/size
22123     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
22124 
22125 Single-int-var-in-mem:  # (payload list var)
22126     0x11/imm32/alloc-id:fake:payload
22127     0x11/imm32/alloc-id:fake
22128     Int-var-in-mem/imm32
22129     0/imm32/next
22130     0/imm32/next
22131 
22132 Int-var-in-mem:  # (payload var)
22133     0x11/imm32/alloc-id:fake:payload
22134     0/imm32/name
22135     0/imm32/name
22136     0x11/imm32/alloc-id:fake
22137     Type-int/imm32
22138     1/imm32/some-block-depth
22139     1/imm32/some-stack-offset
22140     0/imm32/no-register
22141     0/imm32/no-register
22142 
22143 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
22144 Single-byte-var-in-mem:  # (payload list var)
22145     0x11/imm32/alloc-id:fake:payload
22146     0x11/imm32/alloc-id:fake
22147     Byte-var-in-mem/imm32
22148     0/imm32/next
22149     0/imm32/next
22150 
22151 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
22152 Byte-var-in-mem:  # (payload var)
22153     0x11/imm32/alloc-id:fake:payload
22154     0/imm32/name
22155     0/imm32/name
22156     0x11/imm32/alloc-id:fake
22157     Type-byte/imm32
22158     1/imm32/some-block-depth
22159     1/imm32/some-stack-offset
22160     0/imm32/no-register
22161     0/imm32/no-register
22162 
22163 Two-args-int-stack-int-reg:  # (payload list var)
22164     0x11/imm32/alloc-id:fake:payload
22165     0x11/imm32/alloc-id:fake
22166     Int-var-in-mem/imm32
22167     0x11/imm32/alloc-id:fake
22168     Single-int-var-in-some-register/imm32/next
22169 
22170 Two-int-args-in-regs:  # (payload list var)
22171     0x11/imm32/alloc-id:fake:payload
22172     0x11/imm32/alloc-id:fake
22173     Int-var-in-some-register/imm32
22174     0x11/imm32/alloc-id:fake
22175     Single-int-var-in-some-register/imm32/next
22176 
22177 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
22178 Two-args-byte-stack-byte-reg:  # (payload list var)
22179     0x11/imm32/alloc-id:fake:payload
22180     0x11/imm32/alloc-id:fake
22181     Byte-var-in-mem/imm32
22182     0x11/imm32/alloc-id:fake
22183     Single-byte-var-in-some-register/imm32/next
22184 
22185 Two-args-int-reg-int-stack:  # (payload list var)
22186     0x11/imm32/alloc-id:fake:payload
22187     0x11/imm32/alloc-id:fake
22188     Int-var-in-some-register/imm32
22189     0x11/imm32/alloc-id:fake
22190     Single-int-var-in-mem/imm32/next
22191 
22192 Two-args-int-eax-int-literal:  # (payload list var)
22193     0x11/imm32/alloc-id:fake:payload
22194     0x11/imm32/alloc-id:fake
22195     Int-var-in-eax/imm32
22196     0x11/imm32/alloc-id:fake
22197     Single-lit-var/imm32/next
22198 
22199 Int-var-and-literal:  # (payload list var)
22200     0x11/imm32/alloc-id:fake:payload
22201     0x11/imm32/alloc-id:fake
22202     Int-var-in-mem/imm32
22203     0x11/imm32/alloc-id:fake
22204     Single-lit-var/imm32/next
22205 
22206 Int-var-in-register-and-literal:  # (payload list var)
22207     0x11/imm32/alloc-id:fake:payload
22208     0x11/imm32/alloc-id:fake
22209     Int-var-in-some-register/imm32
22210     0x11/imm32/alloc-id:fake
22211     Single-lit-var/imm32/next
22212 
22213 Two-float-args-in-regs:  # (payload list var)
22214     0x11/imm32/alloc-id:fake:payload
22215     0x11/imm32/alloc-id:fake
22216     Float-var-in-some-register/imm32
22217     0x11/imm32/alloc-id:fake
22218     Single-float-var-in-some-register/imm32/next
22219 
22220 Two-args-float-reg-float-stack:  # (payload list var)
22221     0x11/imm32/alloc-id:fake:payload
22222     0x11/imm32/alloc-id:fake
22223     Float-var-in-some-register/imm32
22224     0x11/imm32/alloc-id:fake
22225     Single-float-var-in-mem/imm32/next
22226 
22227 Two-args-float-stack-float-reg:  # (payload list var)
22228     0x11/imm32/alloc-id:fake:payload
22229     0x11/imm32/alloc-id:fake
22230     Float-var-in-mem/imm32
22231     0x11/imm32/alloc-id:fake
22232     Single-float-var-in-some-register/imm32/next
22233 
22234 Single-int-var-in-some-register:  # (payload list var)
22235     0x11/imm32/alloc-id:fake:payload
22236     0x11/imm32/alloc-id:fake
22237     Int-var-in-some-register/imm32
22238     0/imm32/next
22239     0/imm32/next
22240 
22241 Single-addr-var-in-some-register:  # (payload list var)
22242     0x11/imm32/alloc-id:fake:payload
22243     0x11/imm32/alloc-id:fake
22244     Addr-var-in-some-register/imm32
22245     0/imm32/next
22246     0/imm32/next
22247 
22248 Single-byte-var-in-some-register:  # (payload list var)
22249     0x11/imm32/alloc-id:fake:payload
22250     0x11/imm32/alloc-id:fake
22251     Byte-var-in-some-register/imm32
22252     0/imm32/next
22253     0/imm32/next
22254 
22255 Int-var-in-some-register:  # (payload var)
22256     0x11/imm32/alloc-id:fake:payload
22257     0/imm32/name
22258     0/imm32/name
22259     0x11/imm32/alloc-id:fake
22260     Type-int/imm32
22261     1/imm32/some-block-depth
22262     0/imm32/no-stack-offset
22263     0x11/imm32/alloc-id:fake
22264     Any-register/imm32
22265 
22266 Any-register:  # (payload array byte)
22267     0x11/imm32/alloc-id:fake:payload
22268     1/imm32/size
22269     # data
22270     2a/asterisk
22271 
22272 Addr-var-in-some-register:  # (payload var)
22273     0x11/imm32/alloc-id:fake:payload
22274     0/imm32/name
22275     0/imm32/name
22276     0x11/imm32/alloc-id:fake
22277     Type-addr/imm32
22278     1/imm32/some-block-depth
22279     0/imm32/no-stack-offset
22280     0x11/imm32/alloc-id:fake
22281     Any-register/imm32
22282 
22283 Byte-var-in-some-register:  # (payload var)
22284     0x11/imm32/alloc-id:fake:payload
22285     0/imm32/name
22286     0/imm32/name
22287     0x11/imm32/alloc-id:fake
22288     Type-byte/imm32
22289     1/imm32/some-block-depth
22290     0/imm32/no-stack-offset
22291     0x11/imm32/alloc-id:fake
22292     Any-register/imm32
22293 
22294 Single-int-var-in-eax:  # (payload list var)
22295     0x11/imm32/alloc-id:fake:payload
22296     0x11/imm32/alloc-id:fake
22297     Int-var-in-eax/imm32
22298     0/imm32/next
22299     0/imm32/next
22300 
22301 Int-var-in-eax:
22302     0x11/imm32/alloc-id:fake:payload
22303     0/imm32/name
22304     0/imm32/name
22305     0x11/imm32/alloc-id:fake
22306     Type-int/imm32
22307     1/imm32/some-block-depth
22308     0/imm32/no-stack-offset
22309     0x11/imm32/alloc-id:fake
22310     $Register-eax/imm32
22311 
22312 Single-int-var-in-ecx:  # (payload list var)
22313     0x11/imm32/alloc-id:fake:payload
22314     0x11/imm32/alloc-id:fake
22315     Int-var-in-ecx/imm32
22316     0/imm32/next
22317     0/imm32/next
22318 
22319 Int-var-in-ecx:
22320     0x11/imm32/alloc-id:fake:payload
22321     0/imm32/name
22322     0/imm32/name
22323     0x11/imm32/alloc-id:fake
22324     Type-int/imm32
22325     1/imm32/some-block-depth
22326     0/imm32/no-stack-offset
22327     0x11/imm32/alloc-id:fake
22328     $Register-ecx/imm32/register
22329 
22330 Single-int-var-in-edx:  # (payload list var)
22331     0x11/imm32/alloc-id:fake:payload
22332     0x11/imm32/alloc-id:fake
22333     Int-var-in-edx/imm32
22334     0/imm32/next
22335     0/imm32/next
22336 
22337 Int-var-in-edx:  # (payload list var)
22338     0x11/imm32/alloc-id:fake:payload
22339     0/imm32/name
22340     0/imm32/name
22341     0x11/imm32/alloc-id:fake
22342     Type-int/imm32
22343     1/imm32/some-block-depth
22344     0/imm32/no-stack-offset
22345     0x11/imm32/alloc-id:fake
22346     $Register-edx/imm32/register
22347 
22348 Single-int-var-in-ebx:  # (payload list var)
22349     0x11/imm32/alloc-id:fake:payload
22350     0x11/imm32/alloc-id:fake
22351     Int-var-in-ebx/imm32
22352     0/imm32/next
22353     0/imm32/next
22354 
22355 Int-var-in-ebx:  # (payload list var)
22356     0x11/imm32/alloc-id:fake:payload
22357     0/imm32/name
22358     0/imm32/name
22359     0x11/imm32/alloc-id:fake
22360     Type-int/imm32
22361     1/imm32/some-block-depth
22362     0/imm32/no-stack-offset
22363     0x11/imm32/alloc-id:fake
22364     $Register-ebx/imm32/register
22365 
22366 Single-int-var-in-esi:  # (payload list var)
22367     0x11/imm32/alloc-id:fake:payload
22368     0x11/imm32/alloc-id:fake
22369     Int-var-in-esi/imm32
22370     0/imm32/next
22371     0/imm32/next
22372 
22373 Int-var-in-esi:  # (payload list var)
22374     0x11/imm32/alloc-id:fake:payload
22375     0/imm32/name
22376     0/imm32/name
22377     0x11/imm32/alloc-id:fake
22378     Type-int/imm32
22379     1/imm32/some-block-depth
22380     0/imm32/no-stack-offset
22381     0x11/imm32/alloc-id:fake
22382     $Register-esi/imm32/register
22383 
22384 Single-int-var-in-edi:  # (payload list var)
22385     0x11/imm32/alloc-id:fake:payload
22386     0x11/imm32/alloc-id:fake
22387     Int-var-in-edi/imm32
22388     0/imm32/next
22389     0/imm32/next
22390 
22391 Int-var-in-edi:  # (payload list var)
22392     0x11/imm32/alloc-id:fake:payload
22393     0/imm32/name
22394     0/imm32/name
22395     0x11/imm32/alloc-id:fake
22396     Type-int/imm32
22397     1/imm32/some-block-depth
22398     0/imm32/no-stack-offset
22399     0x11/imm32/alloc-id:fake
22400     $Register-edi/imm32/register
22401 
22402 Single-lit-var:  # (payload list var)
22403     0x11/imm32/alloc-id:fake:payload
22404     0x11/imm32/alloc-id:fake
22405     Lit-var/imm32
22406     0/imm32/next
22407     0/imm32/next
22408 
22409 Lit-var:  # (payload var)
22410     0x11/imm32/alloc-id:fake:payload
22411     0/imm32/name
22412     0/imm32/name
22413     0x11/imm32/alloc-id:fake
22414     Type-literal/imm32
22415     1/imm32/some-block-depth
22416     0/imm32/no-stack-offset
22417     0/imm32/no-register
22418     0/imm32/no-register
22419 
22420 Single-float-var-in-mem:  # (payload list var)
22421     0x11/imm32/alloc-id:fake:payload
22422     0x11/imm32/alloc-id:fake
22423     Float-var-in-mem/imm32
22424     0/imm32/next
22425     0/imm32/next
22426 
22427 Float-var-in-mem:  # (payload var)
22428     0x11/imm32/alloc-id:fake:payload
22429     0/imm32/name
22430     0/imm32/name
22431     0x11/imm32/alloc-id:fake
22432     Type-float/imm32
22433     1/imm32/some-block-depth
22434     1/imm32/some-stack-offset
22435     0/imm32/no-register
22436     0/imm32/no-register
22437 
22438 Single-float-var-in-some-register:  # (payload list var)
22439     0x11/imm32/alloc-id:fake:payload
22440     0x11/imm32/alloc-id:fake
22441     Float-var-in-some-register/imm32
22442     0/imm32/next
22443     0/imm32/next
22444 
22445 Float-var-in-some-register:  # (payload var)
22446     0x11/imm32/alloc-id:fake:payload
22447     0/imm32/name
22448     0/imm32/name
22449     0x11/imm32/alloc-id:fake
22450     Type-float/imm32
22451     1/imm32/some-block-depth
22452     0/imm32/no-stack-offset
22453     0x11/imm32/alloc-id:fake
22454     Any-register/imm32
22455 
22456 Type-int:  # (payload type-tree)
22457     0x11/imm32/alloc-id:fake:payload
22458     1/imm32/is-atom
22459     1/imm32/value:int
22460     0/imm32/left:unused
22461     0/imm32/right:null
22462     0/imm32/right:null
22463 
22464 Type-literal:  # (payload type-tree)
22465     0x11/imm32/alloc-id:fake:payload
22466     1/imm32/is-atom
22467     0/imm32/value:literal
22468     0/imm32/left:unused
22469     0/imm32/right:null
22470     0/imm32/right:null
22471 
22472 Type-addr:  # (payload type-tree)
22473     0x11/imm32/alloc-id:fake:payload
22474     1/imm32/is-atom
22475     2/imm32/value:addr
22476     0/imm32/left:unused
22477     0/imm32/right:null
22478     0/imm32/right:null
22479 
22480 Type-byte:  # (payload type-tree)
22481     0x11/imm32/alloc-id:fake:payload
22482     1/imm32/is-atom
22483     8/imm32/value:byte
22484     0/imm32/left:unused
22485     0/imm32/right:null
22486     0/imm32/right:null
22487 
22488 Type-float:  # (payload type-tree)
22489     0x11/imm32/alloc-id:fake:payload
22490     1/imm32/is-atom
22491     0xf/imm32/value:float
22492     0/imm32/left:unused
22493     0/imm32/right:null
22494     0/imm32/right:null
22495 
22496 == code
22497 emit-subx-primitive:  # out: (addr buffered-file), stmt: (addr stmt), primitive: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
22498     # . prologue
22499     55/push-ebp
22500     89/<- %ebp 4/r32/esp
22501     # . save registers
22502     50/push-eax
22503     51/push-ecx
22504     # ecx = primitive
22505     8b/-> *(ebp+0x10) 1/r32/ecx
22506     # emit primitive name
22507     (emit-indent *(ebp+8) *Curr-block-depth)
22508     (lookup *(ecx+0x18) *(ecx+0x1c))  # Primitive-subx-name Primitive-subx-name => eax
22509     (write-buffered *(ebp+8) %eax)
22510     # emit rm32 if necessary
22511     (emit-subx-rm32 *(ebp+8) *(ecx+0x20) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-rm32
22512     # emit xm32 if necessary
22513     (emit-subx-xm32 *(ebp+8) *(ecx+0x34) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-xm32
22514     # emit r32 if necessary
22515     (emit-subx-r32 *(ebp+8) *(ecx+0x24) *(ebp+0xc))  # Primitive-subx-r32
22516     # emit x32 if necessary
22517     (emit-subx-x32 *(ebp+8) *(ecx+0x38) *(ebp+0xc))  # Primitive-subx-x32
22518     # emit imm32 if necessary
22519     (emit-subx-imm32 *(ebp+8) *(ecx+0x28) *(ebp+0xc))  # Primitive-subx-imm32
22520     # emit imm8 if necessary
22521     (emit-subx-imm8 *(ebp+8) *(ecx+0x2c) *(ebp+0xc))  # Primitive-subx-imm8
22522     # emit disp32 if necessary
22523     (emit-subx-disp32 *(ebp+8) *(ecx+0x30) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-disp32
22524     (write-buffered *(ebp+8) Newline)
22525 $emit-subx-primitive:end:
22526     # . restore registers
22527     59/pop-to-ecx
22528     58/pop-to-eax
22529     # . epilogue
22530     89/<- %esp 5/r32/ebp
22531     5d/pop-to-ebp
22532     c3/return
22533 
22534 emit-subx-rm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
22535     # . prologue
22536     55/push-ebp
22537     89/<- %ebp 4/r32/esp
22538     # . save registers
22539     50/push-eax
22540     # if (l == 0) return
22541     81 7/subop/compare *(ebp+0xc) 0/imm32
22542     74/jump-if-= $emit-subx-rm32:end/disp8
22543     # var v/eax: (addr stmt-var)
22544     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
22545     (emit-subx-var-as-rm32 *(ebp+8) %eax)
22546 $emit-subx-rm32:end:
22547     # . restore registers
22548     58/pop-to-eax
22549     # . epilogue
22550     89/<- %esp 5/r32/ebp
22551     5d/pop-to-ebp
22552     c3/return
22553 
22554 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)
22555     # . prologue
22556     55/push-ebp
22557     89/<- %ebp 4/r32/esp
22558     # . save registers
22559     51/push-ecx
22560     # eax = l
22561     8b/-> *(ebp+0xc) 0/r32/eax
22562     # ecx = stmt
22563     8b/-> *(ebp+8) 1/r32/ecx
22564     # if (l == 1) return stmt->inouts
22565     {
22566       3d/compare-eax-and 1/imm32
22567       75/jump-if-!= break/disp8
22568 $get-stmt-operand-from-arg-location:1:
22569       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
22570       eb/jump $get-stmt-operand-from-arg-location:end/disp8
22571     }
22572     # if (l == 2) return stmt->inouts->next
22573     {
22574       3d/compare-eax-and 2/imm32
22575       75/jump-if-!= break/disp8
22576 $get-stmt-operand-from-arg-location:2:
22577       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
22578       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
22579       eb/jump $get-stmt-operand-from-arg-location:end/disp8
22580     }
22581     # if (l == 3) return stmt->outputs
22582     {
22583       3d/compare-eax-and 3/imm32
22584       75/jump-if-!= break/disp8
22585 $get-stmt-operand-from-arg-location:3:
22586       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
22587       eb/jump $get-stmt-operand-from-arg-location:end/disp8
22588     }
22589     # abort
22590     e9/jump $get-stmt-operand-from-arg-location:abort/disp32
22591 $get-stmt-operand-from-arg-location:end:
22592     # . restore registers
22593     59/pop-to-ecx
22594     # . epilogue
22595     89/<- %esp 5/r32/ebp
22596     5d/pop-to-ebp
22597     c3/return
22598 
22599 $get-stmt-operand-from-arg-location:abort:
22600     # error("invalid arg-location " eax)
22601     (write-buffered *(ebp+0x10) "invalid arg-location ")
22602     (write-int32-hex-buffered *(ebp+0x10) %eax)
22603     (write-buffered *(ebp+0x10) Newline)
22604     (flush *(ebp+0x10))
22605     (stop *(ebp+0x14) 1)
22606     # never gets here
22607 
22608 emit-subx-r32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
22609     # . prologue
22610     55/push-ebp
22611     89/<- %ebp 4/r32/esp
22612     # . save registers
22613     50/push-eax
22614     51/push-ecx
22615     # if (l == 0) return
22616     81 7/subop/compare *(ebp+0xc) 0/imm32
22617     0f 84/jump-if-= $emit-subx-r32:end/disp32
22618     # var v/eax: (addr stmt-var)
22619     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
22620     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
22621     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
22622 #?     (write-buffered Stderr "looking up ")
22623 #?     (write-buffered Stderr %eax)
22624 #?     (write-buffered Stderr Newline)
22625 #?     (flush Stderr)
22626     (maybe-get Mu-registers %eax 0xc)  # => eax: (addr register-index)
22627     (write-buffered *(ebp+8) Space)
22628     (write-int32-hex-buffered *(ebp+8) *eax)
22629     (write-buffered *(ebp+8) "/r32")
22630 $emit-subx-r32:end:
22631     # . restore registers
22632     59/pop-to-ecx
22633     58/pop-to-eax
22634     # . epilogue
22635     89/<- %esp 5/r32/ebp
22636     5d/pop-to-ebp
22637     c3/return
22638 
22639 emit-subx-xm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
22640     # . prologue
22641     55/push-ebp
22642     89/<- %ebp 4/r32/esp
22643     # . save registers
22644     50/push-eax
22645     # if (l == 0) return
22646     81 7/subop/compare *(ebp+0xc) 0/imm32
22647     74/jump-if-= $emit-subx-xm32:end/disp8
22648     # var v/eax: (addr stmt-var)
22649     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
22650     (emit-subx-var-as-xm32 *(ebp+8) %eax)
22651 $emit-subx-xm32:end:
22652     # . restore registers
22653     58/pop-to-eax
22654     # . epilogue
22655     89/<- %esp 5/r32/ebp
22656     5d/pop-to-ebp
22657     c3/return
22658 
22659 emit-subx-x32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
22660     # . prologue
22661     55/push-ebp
22662     89/<- %ebp 4/r32/esp
22663     # . save registers
22664     50/push-eax
22665     51/push-ecx
22666     # if (l == 0) return
22667     81 7/subop/compare *(ebp+0xc) 0/imm32
22668     0f 84/jump-if-= $emit-subx-x32:end/disp32
22669     # var v/eax: (addr stmt-var)
22670     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
22671     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
22672     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
22673 #?     (write-buffered Stderr "looking up ")
22674 #?     (write-buffered Stderr %eax)
22675 #?     (write-buffered Stderr Newline)
22676 #?     (flush Stderr)
22677     (maybe-get Mu-registers %eax 0xc)  # => eax: (addr register-index)
22678     (write-buffered *(ebp+8) Space)
22679     (write-int32-hex-buffered *(ebp+8) *eax)
22680     (write-buffered *(ebp+8) "/x32")
22681 $emit-subx-x32:end:
22682     # . restore registers
22683     59/pop-to-ecx
22684     58/pop-to-eax
22685     # . epilogue
22686     89/<- %esp 5/r32/ebp
22687     5d/pop-to-ebp
22688     c3/return
22689 
22690 emit-subx-imm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
22691     # . prologue
22692     55/push-ebp
22693     89/<- %ebp 4/r32/esp
22694     # . save registers
22695     50/push-eax
22696     51/push-ecx
22697     # if (l == 0) return
22698     81 7/subop/compare *(ebp+0xc) 0/imm32
22699     0f 84/jump-if-= $emit-subx-imm32:end/disp32
22700     # var v/eax: (handle var)
22701     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
22702     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
22703     (lookup *eax *(eax+4))  # Var-name Var-name => eax
22704     (write-buffered *(ebp+8) Space)
22705     (write-buffered *(ebp+8) %eax)
22706     (write-buffered *(ebp+8) "/imm32")
22707 $emit-subx-imm32:end:
22708     # . restore registers
22709     59/pop-to-ecx
22710     58/pop-to-eax
22711     # . epilogue
22712     89/<- %esp 5/r32/ebp
22713     5d/pop-to-ebp
22714     c3/return
22715 
22716 emit-subx-imm8:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
22717     # . prologue
22718     55/push-ebp
22719     89/<- %ebp 4/r32/esp
22720     # . save registers
22721     50/push-eax
22722     51/push-ecx
22723     # if (l == 0) return
22724     81 7/subop/compare *(ebp+0xc) 0/imm32
22725     0f 84/jump-if-= $emit-subx-imm32:end/disp32
22726     # var v/eax: (handle var)
22727     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
22728     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
22729     (lookup *eax *(eax+4))  # Var-name Var-name => eax
22730     (write-buffered *(ebp+8) Space)
22731     (write-buffered *(ebp+8) %eax)
22732     (write-buffered *(ebp+8) "/imm8")
22733 $emit-subx-imm8:end:
22734     # . restore registers
22735     59/pop-to-ecx
22736     58/pop-to-eax
22737     # . epilogue
22738     89/<- %esp 5/r32/ebp
22739     5d/pop-to-ebp
22740     c3/return
22741 
22742 emit-subx-disp32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
22743     # . prologue
22744     55/push-ebp
22745     89/<- %ebp 4/r32/esp
22746     # . save registers
22747     50/push-eax
22748     51/push-ecx
22749     # if (location == 0) return
22750     81 7/subop/compare *(ebp+0xc) 0/imm32
22751     0f 84/jump-if-= $emit-subx-disp32:end/disp32
22752     # var v/eax: (addr stmt-var)
22753     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
22754     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
22755     (lookup *eax *(eax+4))  # Var-name Var-name => eax
22756     (write-buffered *(ebp+8) Space)
22757     (write-buffered *(ebp+8) %eax)
22758     # hack: if instruction operation starts with "break", emit ":break"
22759     # var name/ecx: (addr array byte) = lookup(stmt->operation)
22760     8b/-> *(ebp+0x10) 0/r32/eax
22761     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
22762     89/<- %ecx 0/r32/eax
22763     {
22764       (string-starts-with? %ecx "break")  # => eax
22765       3d/compare-eax-and 0/imm32/false
22766       74/jump-if-= break/disp8
22767       (write-buffered *(ebp+8) ":break")
22768     }
22769     # hack: if instruction operation starts with "loop", emit ":loop"
22770     {
22771       (string-starts-with? %ecx "loop")  # => eax
22772       3d/compare-eax-and 0/imm32/false
22773       74/jump-if-= break/disp8
22774       (write-buffered *(ebp+8) ":loop")
22775     }
22776     (write-buffered *(ebp+8) "/disp32")
22777 $emit-subx-disp32:end:
22778     # . restore registers
22779     59/pop-to-ecx
22780     58/pop-to-eax
22781     # . epilogue
22782     89/<- %esp 5/r32/ebp
22783     5d/pop-to-ebp
22784     c3/return
22785 
22786 emit-call:  # out: (addr buffered-file), stmt: (addr stmt)
22787     # . prologue
22788     55/push-ebp
22789     89/<- %ebp 4/r32/esp
22790     # . save registers
22791     50/push-eax
22792     51/push-ecx
22793     #
22794     (emit-indent *(ebp+8) *Curr-block-depth)
22795     (write-buffered *(ebp+8) "(")
22796     # ecx = stmt
22797     8b/-> *(ebp+0xc) 1/r32/ecx
22798     # - emit function name
22799     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
22800     (write-buffered *(ebp+8) %eax)
22801     # - emit arguments
22802     # var curr/eax: (addr stmt-var) = lookup(stmt->inouts)
22803     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
22804     {
22805       # if (curr == null) break
22806       3d/compare-eax-and 0/imm32
22807       74/jump-if-= break/disp8
22808       #
22809       (emit-subx-call-operand *(ebp+8) %eax)
22810       # curr = lookup(curr->next)
22811       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
22812       eb/jump loop/disp8
22813     }
22814     #
22815     (write-buffered *(ebp+8) ")\n")
22816 $emit-call:end:
22817     # . restore registers
22818     59/pop-to-ecx
22819     58/pop-to-eax
22820     # . epilogue
22821     89/<- %esp 5/r32/ebp
22822     5d/pop-to-ebp
22823     c3/return
22824 
22825 emit-subx-call-operand:  # out: (addr buffered-file), s: (addr stmt-var)
22826     # shares code with emit-subx-var-as-rm32
22827     # . prologue
22828     55/push-ebp
22829     89/<- %ebp 4/r32/esp
22830     # . save registers
22831     50/push-eax
22832     51/push-ecx
22833     56/push-esi
22834     # ecx = s
22835     8b/-> *(ebp+0xc) 1/r32/ecx
22836     # var operand/esi: (addr var) = lookup(s->value)
22837     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
22838     89/<- %esi 0/r32/eax
22839     # if (operand->register && !s->is-deref?) emit "%__"
22840     {
22841 $emit-subx-call-operand:check-for-register-direct:
22842       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
22843       74/jump-if-= break/disp8
22844       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
22845       75/jump-if-!= break/disp8
22846 $emit-subx-call-operand:register-direct:
22847       (write-buffered *(ebp+8) " %")
22848       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
22849       (write-buffered *(ebp+8) %eax)
22850       e9/jump $emit-subx-call-operand:end/disp32
22851     }
22852     # else if (operand->register && s->is-deref?) emit "*__"
22853     {
22854 $emit-subx-call-operand:check-for-register-indirect:
22855       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
22856       74/jump-if-= break/disp8
22857       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
22858       74/jump-if-= break/disp8
22859 $emit-subx-call-operand:register-indirect:
22860       (emit-subx-call-operand-register-indirect *(ebp+8) %esi)
22861       e9/jump $emit-subx-call-operand:end/disp32
22862     }
22863     # else if (operand->stack-offset) emit "*(ebp+__)"
22864     {
22865       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
22866       74/jump-if-= break/disp8
22867 $emit-subx-call-operand:stack:
22868       (emit-subx-call-operand-stack *(ebp+8) %esi)
22869       e9/jump $emit-subx-call-operand:end/disp32
22870     }
22871     # else if (operand->type == literal) emit "__"
22872     {
22873       (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
22874       81 7/subop/compare *(eax+4) 0/imm32  # Type-tree-left
22875       75/jump-if-!= break/disp8
22876 $emit-subx-call-operand:literal:
22877       (write-buffered *(ebp+8) Space)
22878       (lookup *esi *(esi+4))  # Var-name Var-name => eax
22879       (write-buffered *(ebp+8) %eax)
22880     }
22881 $emit-subx-call-operand:end:
22882     # . restore registers
22883     5e/pop-to-esi
22884     59/pop-to-ecx
22885     58/pop-to-eax
22886     # . epilogue
22887     89/<- %esp 5/r32/ebp
22888     5d/pop-to-ebp
22889     c3/return
22890 
22891 emit-subx-call-operand-register-indirect:  # out: (addr buffered-file), v: (addr var)
22892     # . prologue
22893     55/push-ebp
22894     89/<- %ebp 4/r32/esp
22895     # . save registers
22896     50/push-eax
22897     51/push-ecx
22898     56/push-esi
22899     # esi = v
22900     8b/-> *(ebp+0xc) 6/r32/esi
22901     # var size/ecx: int = size-of-deref(v)
22902     (size-of-deref %esi)  # => eax
22903     89/<- %ecx 0/r32/eax
22904     # var reg-name/esi: (addr array byte) = lookup(v->register)
22905     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
22906     89/<- %esi 0/r32/eax
22907     # TODO: assert size is a multiple of 4
22908     # var i/eax: int = 0
22909     b8/copy-to-eax 0/imm32
22910     {
22911 $emit-subx-call-operand-register-indirect:loop:
22912       # if (i >= size) break
22913       39/compare %eax 1/r32/ecx
22914       7d/jump-if->= break/disp8
22915       # emit " *(" v->register "+" i ")"
22916       (write-buffered *(ebp+8) " *(")
22917       (write-buffered *(ebp+8) %esi)
22918       (write-buffered *(ebp+8) "+")
22919       (write-int32-hex-buffered *(ebp+8) %eax)
22920       (write-buffered *(ebp+8) ")")
22921       # i += 4
22922       05/add-to-eax 4/imm32
22923       #
22924       eb/jump loop/disp8
22925     }
22926 $emit-subx-call-operand-register-indirect:end:
22927     # . restore registers
22928     5e/pop-to-esi
22929     59/pop-to-ecx
22930     58/pop-to-eax
22931     # . epilogue
22932     89/<- %esp 5/r32/ebp
22933     5d/pop-to-ebp
22934     c3/return
22935 
22936 emit-subx-call-operand-stack:  # out: (addr buffered-file), v: (addr var)
22937     # . prologue
22938     55/push-ebp
22939     89/<- %ebp 4/r32/esp
22940     # . save registers
22941     50/push-eax
22942     51/push-ecx
22943     56/push-esi
22944     # esi = v
22945     8b/-> *(ebp+0xc) 6/r32/esi
22946     # var curr/ecx: int = v->offset
22947     8b/-> *(esi+0x14) 1/r32/ecx  # Var-offset
22948     # var max/eax: int = v->offset + size-of(v)
22949     (size-of %esi)  # => eax
22950     # TODO: assert size is a multiple of 4
22951     01/add-to %eax 1/r32/ecx
22952     {
22953 $emit-subx-call-operand-stack:loop:
22954       # if (curr >= max) break
22955       39/compare %ecx 0/r32/eax
22956       7d/jump-if->= break/disp8
22957       # emit " *(ebp+" curr ")"
22958       (write-buffered *(ebp+8) " *(ebp+")
22959       (write-int32-hex-buffered *(ebp+8) %ecx)
22960       (write-buffered *(ebp+8) ")")
22961       # i += 4
22962       81 0/subop/add %ecx 4/imm32
22963       #
22964       eb/jump loop/disp8
22965     }
22966 $emit-subx-call-operand-stack:end:
22967     # . restore registers
22968     5e/pop-to-esi
22969     59/pop-to-ecx
22970     58/pop-to-eax
22971     # . epilogue
22972     89/<- %esp 5/r32/ebp
22973     5d/pop-to-ebp
22974     c3/return
22975 
22976 emit-subx-var-as-rm32:  # out: (addr buffered-file), s: (addr stmt-var)
22977     # . prologue
22978     55/push-ebp
22979     89/<- %ebp 4/r32/esp
22980     # . save registers
22981     50/push-eax
22982     51/push-ecx
22983     56/push-esi
22984     # ecx = s
22985     8b/-> *(ebp+0xc) 1/r32/ecx
22986     # var operand/esi: (addr var) = lookup(s->value)
22987     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
22988     89/<- %esi 0/r32/eax
22989     # if (operand->register && s->is-deref?) emit "*__"
22990     {
22991 $emit-subx-var-as-rm32:check-for-register-indirect:
22992       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
22993       74/jump-if-= break/disp8
22994       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
22995       74/jump-if-= break/disp8
22996 $emit-subx-var-as-rm32:register-indirect:
22997       (write-buffered *(ebp+8) " *")
22998       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
22999       (write-buffered *(ebp+8) %eax)
23000       e9/jump $emit-subx-var-as-rm32:end/disp32
23001     }
23002     # if (operand->register && !s->is-deref?) emit "%__"
23003     {
23004 $emit-subx-var-as-rm32:check-for-register-direct:
23005       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
23006       74/jump-if-= break/disp8
23007       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
23008       75/jump-if-!= break/disp8
23009 $emit-subx-var-as-rm32:register-direct:
23010       (write-buffered *(ebp+8) " %")
23011       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
23012       (write-buffered *(ebp+8) %eax)
23013       e9/jump $emit-subx-var-as-rm32:end/disp32
23014     }
23015     # else if (operand->stack-offset) emit "*(ebp+__)"
23016     {
23017       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
23018       74/jump-if-= break/disp8
23019 $emit-subx-var-as-rm32:stack:
23020       (write-buffered *(ebp+8) Space)
23021       (write-buffered *(ebp+8) "*(ebp+")
23022       (write-int32-hex-buffered *(ebp+8) *(esi+0x14))  # Var-offset
23023       (write-buffered *(ebp+8) ")")
23024     }
23025 $emit-subx-var-as-rm32:end:
23026     # . restore registers
23027     5e/pop-to-esi
23028     59/pop-to-ecx
23029     58/pop-to-eax
23030     # . epilogue
23031     89/<- %esp 5/r32/ebp
23032     5d/pop-to-ebp
23033     c3/return
23034 
23035 # xm32 is like rm32, except that direct mode uses floating-point registers.
23036 # Indirect mode is the same.
23037 emit-subx-var-as-xm32:  # out: (addr buffered-file), s: (addr stmt-var)
23038     # . prologue
23039     55/push-ebp
23040     89/<- %ebp 4/r32/esp
23041     # . save registers
23042     50/push-eax
23043     51/push-ecx
23044     56/push-esi
23045     # ecx = s
23046     8b/-> *(ebp+0xc) 1/r32/ecx
23047     # var operand/esi: (addr var) = lookup(s->value)
23048     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
23049     89/<- %esi 0/r32/eax
23050     # if (operand->register && s->is-deref?) emit "*__"
23051     {
23052 $emit-subx-var-as-xm32:check-for-register-indirect:
23053       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
23054       74/jump-if-= break/disp8
23055       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
23056       74/jump-if-= break/disp8
23057 $emit-subx-var-as-xm32:register-indirect:
23058       (write-buffered *(ebp+8) " *")
23059       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
23060       (write-buffered *(ebp+8) %eax)
23061       e9/jump $emit-subx-var-as-xm32:end/disp32
23062     }
23063     # if (operand->register && !s->is-deref?) emit "3/mod __/xm32"
23064     {
23065 $emit-subx-var-as-xm32:check-for-register-direct:
23066       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
23067       0f 84/jump-if-= break/disp32
23068       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
23069       75/jump-if-!= break/disp8
23070 $emit-subx-var-as-xm32:register-direct:
23071       (write-buffered *(ebp+8) " 3/mod ")
23072       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
23073       (maybe-get Mu-registers %eax 0xc)  # => eax: (addr register-index)
23074       (write-int32-hex-buffered *(ebp+8) *eax)
23075       (write-buffered *(ebp+8) "/xm32")
23076       e9/jump $emit-subx-var-as-xm32:end/disp32
23077     }
23078     # else if (operand->stack-offset) emit "*(ebp+__)"
23079     {
23080       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
23081       74/jump-if-= break/disp8
23082 $emit-subx-var-as-xm32:stack:
23083       (write-buffered *(ebp+8) Space)
23084       (write-buffered *(ebp+8) "*(ebp+")
23085       (write-int32-hex-buffered *(ebp+8) *(esi+0x14))  # Var-offset
23086       (write-buffered *(ebp+8) ")")
23087     }
23088 $emit-subx-var-as-xm32:end:
23089     # . restore registers
23090     5e/pop-to-esi
23091     59/pop-to-ecx
23092     58/pop-to-eax
23093     # . epilogue
23094     89/<- %esp 5/r32/ebp
23095     5d/pop-to-ebp
23096     c3/return
23097 
23098 find-matching-primitive:  # primitives: (addr primitive), stmt: (addr stmt) -> result/eax: (addr primitive)
23099     # . prologue
23100     55/push-ebp
23101     89/<- %ebp 4/r32/esp
23102     # . save registers
23103     51/push-ecx
23104     # var curr/ecx: (addr primitive) = primitives
23105     8b/-> *(ebp+8) 1/r32/ecx
23106     {
23107 $find-matching-primitive:loop:
23108       # if (curr == null) break
23109       81 7/subop/compare %ecx 0/imm32
23110       74/jump-if-= break/disp8
23111       # if match(curr, stmt) return curr
23112       {
23113         (mu-stmt-matches-primitive? *(ebp+0xc) %ecx)  # => eax
23114         3d/compare-eax-and 0/imm32/false
23115         74/jump-if-= break/disp8
23116         89/<- %eax 1/r32/ecx
23117         eb/jump $find-matching-primitive:end/disp8
23118       }
23119 $find-matching-primitive:next-primitive:
23120       # curr = curr->next
23121       (lookup *(ecx+0x3c) *(ecx+0x40))  # Primitive-next Primitive-next => eax
23122       89/<- %ecx 0/r32/eax
23123       #
23124       e9/jump loop/disp32
23125     }
23126     # return null
23127     b8/copy-to-eax 0/imm32
23128 $find-matching-primitive:end:
23129     # . restore registers
23130     59/pop-to-ecx
23131     # . epilogue
23132     89/<- %esp 5/r32/ebp
23133     5d/pop-to-ebp
23134     c3/return
23135 
23136 mu-stmt-matches-primitive?:  # stmt: (addr stmt), primitive: (addr primitive) -> result/eax: boolean
23137     # A mu stmt matches a primitive if the name matches, all the inout vars
23138     # match, and all the output vars match.
23139     # Vars match if types match and registers match.
23140     # In addition, a stmt output matches a primitive's output if types match
23141     # and the primitive has a wildcard register.
23142     # . prologue
23143     55/push-ebp
23144     89/<- %ebp 4/r32/esp
23145     # . save registers
23146     51/push-ecx
23147     52/push-edx
23148     53/push-ebx
23149     56/push-esi
23150     57/push-edi
23151     # ecx = stmt
23152     8b/-> *(ebp+8) 1/r32/ecx
23153     # edx = primitive
23154     8b/-> *(ebp+0xc) 2/r32/edx
23155     {
23156 $mu-stmt-matches-primitive?:check-name:
23157       # if (primitive->name != stmt->operation) return false
23158       # . var esi: (addr array byte) = lookup(stmt->operation)
23159       (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
23160       89/<- %esi 0/r32/eax
23161       # . var edi: (addr array byte) = lookup(primitive->name)
23162       (lookup *edx *(edx+4))  # Primitive-name Primitive-name => eax
23163 #?       (write-buffered Stderr %eax)
23164 #?       (write-buffered Stderr Newline)
23165 #?       (flush Stderr)
23166       89/<- %edi 0/r32/eax
23167       (string-equal? %esi %edi)  # => eax
23168       3d/compare-eax-and 0/imm32/false
23169       75/jump-if-!= break/disp8
23170       b8/copy-to-eax 0/imm32
23171       e9/jump $mu-stmt-matches-primitive?:end/disp32
23172     }
23173     # var curr/esi: (addr stmt-var) = lookup(stmt->inouts)
23174     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
23175     89/<- %esi 0/r32/eax
23176     # var curr2/edi: (addr list var) = lookup(primitive->inouts)
23177     (lookup *(edx+8) *(edx+0xc))  # Primitive-inouts Primitive-inouts => eax
23178     89/<- %edi 0/r32/eax
23179     {
23180 $mu-stmt-matches-primitive?:inouts-loop:
23181       # if (curr == 0 && curr2 == 0) move on to check outputs
23182       {
23183 $mu-stmt-matches-primitive?:check-both-inouts-null:
23184         81 7/subop/compare %esi 0/imm32
23185         75/jump-if-!= break/disp8
23186 $mu-stmt-matches-primitive?:stmt-inout-null:
23187         81 7/subop/compare %edi 0/imm32
23188         0f 84/jump-if-= $mu-stmt-matches-primitive?:check-outputs/disp32
23189 $mu-stmt-matches-primitive?:stmt-inout-null-and-prim-inout-not-null:
23190         # return false
23191         b8/copy-to-eax 0/imm32/false
23192         e9/jump $mu-stmt-matches-primitive?:end/disp32
23193       }
23194       # if (curr2 == 0) return false
23195       {
23196 $mu-stmt-matches-primitive?:check-prim-inout-null:
23197         81 7/subop/compare %edi 0/imm32
23198         75/jump-if-!= break/disp8
23199 $mu-stmt-matches-primitive?:prim-inout-null:
23200         b8/copy-to-eax 0/imm32/false
23201         e9/jump $mu-stmt-matches-primitive?:end/disp32
23202       }
23203       # if (curr != curr2) return false
23204       {
23205 $mu-stmt-matches-primitive?:check-inouts-match:
23206         (lookup *edi *(edi+4))  # List-value List-value => eax
23207         (operand-matches-primitive? %esi %eax)  # => eax
23208         3d/compare-eax-and 0/imm32/false
23209         75/jump-if-!= break/disp8
23210 $mu-stmt-matches-primitive?:inouts-match:
23211         b8/copy-to-eax 0/imm32/false
23212         e9/jump $mu-stmt-matches-primitive?:end/disp32
23213       }
23214 $mu-stmt-matches-primitive?:next-inout:
23215       # curr = lookup(curr->next)
23216       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
23217       89/<- %esi 0/r32/eax
23218       # curr2 = lookup(curr2->next)
23219       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
23220       89/<- %edi 0/r32/eax
23221       #
23222       e9/jump loop/disp32
23223     }
23224 $mu-stmt-matches-primitive?:check-outputs:
23225     # var curr/esi: (addr stmt-var) = lookup(stmt->outputs)
23226     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
23227     89/<- %esi 0/r32/eax
23228     # var curr2/edi: (addr list var) = lookup(primitive->outputs)
23229     (lookup *(edx+0x10) *(edx+0x14))  # Primitive-outputs Primitive-outputs => eax
23230     89/<- %edi 0/r32/eax
23231     {
23232 $mu-stmt-matches-primitive?:outputs-loop:
23233       # if (curr == 0) return (curr2 == 0)
23234       {
23235 $mu-stmt-matches-primitive?:check-both-outputs-null:
23236         81 7/subop/compare %esi 0/imm32
23237         75/jump-if-!= break/disp8
23238         {
23239 $mu-stmt-matches-primitive?:stmt-output-null:
23240           81 7/subop/compare %edi 0/imm32
23241           75/jump-if-!= break/disp8
23242 $mu-stmt-matches-primitive?:both-outputs-null:
23243           # return true
23244           b8/copy-to-eax 1/imm32
23245           e9/jump $mu-stmt-matches-primitive?:end/disp32
23246         }
23247 $mu-stmt-matches-primitive?:stmt-output-null-and-prim-output-not-null:
23248         # return false
23249         b8/copy-to-eax 0/imm32
23250         e9/jump $mu-stmt-matches-primitive?:end/disp32
23251       }
23252       # if (curr2 == 0) return false
23253       {
23254 $mu-stmt-matches-primitive?:check-prim-output-null:
23255         81 7/subop/compare %edi 0/imm32
23256         75/jump-if-!= break/disp8
23257 $mu-stmt-matches-primitive?:prim-output-is-null:
23258         b8/copy-to-eax 0/imm32
23259         e9/jump $mu-stmt-matches-primitive?:end/disp32
23260       }
23261       # if (curr != curr2) return false
23262       {
23263 $mu-stmt-matches-primitive?:check-outputs-match:
23264         (lookup *edi *(edi+4))  # List-value List-value => eax
23265         (operand-matches-primitive? %esi %eax)  # => eax
23266         3d/compare-eax-and 0/imm32/false
23267         75/jump-if-!= break/disp8
23268 $mu-stmt-matches-primitive?:outputs-match:
23269         b8/copy-to-eax 0/imm32
23270         e9/jump $mu-stmt-matches-primitive?:end/disp32
23271       }
23272 $mu-stmt-matches-primitive?:next-output:
23273       # curr = lookup(curr->next)
23274       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
23275       89/<- %esi 0/r32/eax
23276       # curr2 = lookup(curr2->next)
23277       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
23278       89/<- %edi 0/r32/eax
23279       #
23280       e9/jump loop/disp32
23281     }
23282 $mu-stmt-matches-primitive?:return-true:
23283     b8/copy-to-eax 1/imm32
23284 $mu-stmt-matches-primitive?:end:
23285     # . restore registers
23286     5f/pop-to-edi
23287     5e/pop-to-esi
23288     5b/pop-to-ebx
23289     5a/pop-to-edx
23290     59/pop-to-ecx
23291     # . epilogue
23292     89/<- %esp 5/r32/ebp
23293     5d/pop-to-ebp
23294     c3/return
23295 
23296 operand-matches-primitive?:  # s: (addr stmt-var), prim-var: (addr var) -> result/eax: boolean
23297     # . prologue
23298     55/push-ebp
23299     89/<- %ebp 4/r32/esp
23300     # . save registers
23301     51/push-ecx
23302     52/push-edx
23303     53/push-ebx
23304     56/push-esi
23305     57/push-edi
23306     # ecx = s
23307     8b/-> *(ebp+8) 1/r32/ecx
23308     # var var/esi: (addr var) = lookup(s->value)
23309     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
23310     89/<- %esi 0/r32/eax
23311     # edi = prim-var
23312     8b/-> *(ebp+0xc) 7/r32/edi
23313 $operand-matches-primitive?:check-type:
23314     # if !category-match?(var->type, prim-var->type) return false
23315     # . var vtype/ebx: (addr type-tree) = lookup(var->type)
23316     (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
23317     89/<- %ebx 0/r32/eax
23318     # . var ptype/eax: (addr type-tree) = lookup(prim-var->type)
23319     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
23320     (subx-type-category-match? %ebx %eax)  # => eax
23321     3d/compare-eax-and 0/imm32/false
23322     0f 84/jump-if-= $operand-matches-primitive?:return-false/disp32
23323     {
23324 $operand-matches-primitive?:check-register:
23325       # if prim-var is in memory and var is in register but dereference, match
23326       {
23327         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
23328         0f 85/jump-if-!= break/disp32
23329         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
23330         74/jump-if-= break/disp8
23331         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
23332         74/jump-if-= break/disp8
23333 $operand-matches-primitive?:var-deref-match:
23334         e9/jump $operand-matches-primitive?:return-true/disp32
23335       }
23336       # if prim-var is in register and var is in register but dereference, no match
23337       {
23338         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
23339         0f 84/jump-if-= break/disp32
23340         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
23341         0f 84/jump-if-= break/disp32
23342         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
23343         74/jump-if-= break/disp8
23344 $operand-matches-primitive?:var-deref-no-match:
23345         e9/jump $operand-matches-primitive?:return-false/disp32
23346       }
23347       # return false if var->register doesn't match prim-var->register
23348       {
23349         # if register addresses are equal, it's a match
23350         # var vreg/ebx: (addr array byte) = lookup(var->register)
23351         (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
23352         89/<- %ebx 0/r32/eax
23353         # var preg/ecx: (addr array byte) = lookup(prim-var->register)
23354         (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
23355         89/<- %ecx 0/r32/eax
23356         # if (vreg == preg) break
23357         39/compare %ecx 3/r32/ebx
23358         74/jump-if-= break/disp8
23359 $operand-matches-primitive?:var-register-no-match:
23360         # if either address is 0, return false
23361         81 7/subop/compare %ebx 0/imm32
23362         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
23363         81 7/subop/compare %ecx 0/imm32
23364         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
23365         # if prim-var->register is wildcard, it's a match
23366         (string-equal? %ecx "*")  # Any-register => eax
23367         3d/compare-eax-and 0/imm32/false
23368         75/jump-if-!= break/disp8
23369 $operand-matches-primitive?:wildcard-no-match:
23370         # if string contents aren't equal, return false
23371         (string-equal? %ecx %ebx)  # => eax
23372         3d/compare-eax-and 0/imm32/false
23373         74/jump-if-= $operand-matches-primitive?:return-false/disp8
23374       }
23375     }
23376 $operand-matches-primitive?:return-true:
23377     b8/copy-to-eax 1/imm32/true
23378     eb/jump $operand-matches-primitive?:end/disp8
23379 $operand-matches-primitive?:return-false:
23380     b8/copy-to-eax 0/imm32/false
23381 $operand-matches-primitive?:end:
23382     # . restore registers
23383     5f/pop-to-edi
23384     5e/pop-to-esi
23385     5b/pop-to-ebx
23386     5a/pop-to-edx
23387     59/pop-to-ecx
23388     # . epilogue
23389     89/<- %esp 5/r32/ebp
23390     5d/pop-to-ebp
23391     c3/return
23392 
23393 find-matching-function:  # functions: (addr function), stmt: (addr stmt) -> result/eax: (addr function)
23394     # . prologue
23395     55/push-ebp
23396     89/<- %ebp 4/r32/esp
23397     # . save registers
23398     51/push-ecx
23399     # var curr/ecx: (handle function) = functions
23400     8b/-> *(ebp+8) 1/r32/ecx
23401     {
23402       # if (curr == null) break
23403       81 7/subop/compare %ecx 0/imm32
23404       74/jump-if-= break/disp8
23405 #?       (write-buffered Stderr "iter\n")
23406 #?       (flush Stderr)
23407       # if match(stmt, curr) return curr
23408       {
23409         (mu-stmt-matches-function? *(ebp+0xc) %ecx)  # => eax
23410         3d/compare-eax-and 0/imm32/false
23411         74/jump-if-= break/disp8
23412         89/<- %eax 1/r32/ecx
23413         eb/jump $find-matching-function:end/disp8
23414       }
23415       # curr = curr->next
23416       (lookup *(ecx+0x20) *(ecx+0x24))  # Function-next Function-next => eax
23417       89/<- %ecx 0/r32/eax
23418       #
23419       eb/jump loop/disp8
23420     }
23421     # return null
23422     b8/copy-to-eax 0/imm32
23423 $find-matching-function:end:
23424     # . restore registers
23425     59/pop-to-ecx
23426     # . epilogue
23427     89/<- %esp 5/r32/ebp
23428     5d/pop-to-ebp
23429     c3/return
23430 
23431 # Just compare names; user-defined functions don't support overloading yet.
23432 mu-stmt-matches-function?:  # stmt: (addr stmt1), function: (addr function) -> result/eax: boolean
23433     # . prologue
23434     55/push-ebp
23435     89/<- %ebp 4/r32/esp
23436     # . save registers
23437     51/push-ecx
23438     # return function->name == stmt->operation
23439     # ecx = lookup(stmt->operation)
23440     8b/-> *(ebp+8) 0/r32/eax
23441     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
23442     89/<- %ecx 0/r32/eax
23443     # eax = lookup(function->name)
23444     8b/-> *(ebp+0xc) 0/r32/eax
23445     (lookup *eax *(eax+4))  # Function-name Function-name => eax
23446     (string-equal? %eax %ecx)  # => eax
23447 $mu-stmt-matches-function?:end:
23448     # . restore registers
23449     59/pop-to-ecx
23450     # . epilogue
23451     89/<- %esp 5/r32/ebp
23452     5d/pop-to-ebp
23453     c3/return
23454 
23455 # Type-checking happens elsewhere. This method is for selecting between
23456 # primitives.
23457 subx-type-category-match?:  # a: (addr type-tree), b: (addr type-tree) -> result/eax: boolean
23458     # . prologue
23459     55/push-ebp
23460     89/<- %ebp 4/r32/esp
23461     # . save registers
23462     51/push-ecx
23463     # var cata/ecx: int = type-category(a)
23464     (type-category *(ebp+8))  # => eax
23465     89/<- %ecx 0/r32/eax
23466     # var catb/eax: int = type-category(b)
23467     (type-category *(ebp+0xc))  # => eax
23468     # return cata == catb
23469     39/compare %eax 1/r32/ecx
23470     0f 94/set-byte-if-= %al
23471     81 4/subop/and %eax 0xff/imm32
23472 $subx-type-category-match?:end:
23473     # . restore registers
23474     59/pop-to-ecx
23475     # . epilogue
23476     89/<- %esp 5/r32/ebp
23477     5d/pop-to-ebp
23478     c3/return
23479 
23480 type-category:  # a: (addr type-tree) -> result/eax: int
23481     # . prologue
23482     55/push-ebp
23483     89/<- %ebp 4/r32/esp
23484     # . save registers
23485     51/push-ecx
23486     # var lit?/ecx: boolean = is-literal-type?(a)
23487     (is-simple-mu-type? *(ebp+8) 0)  # => eax
23488     89/<- %ecx 0/r32/eax
23489     # var float?/eax: int = is-float?(a)
23490     (is-simple-mu-type? *(ebp+8) 0xf)  # => eax
23491     # set bits for lit? and float?
23492     c1/shift 4/subop/left %ecx 1/imm8
23493     09/or %eax 1/r32/ecx
23494 $type-category:end:
23495     # . restore registers
23496     59/pop-to-ecx
23497     # . epilogue
23498     89/<- %esp 5/r32/ebp
23499     5d/pop-to-ebp
23500     c3/return
23501 
23502 is-simple-mu-type?:  # a: (addr type-tree), n: type-id -> result/eax: boolean
23503     # . prologue
23504     55/push-ebp
23505     89/<- %ebp 4/r32/esp
23506     # . save registers
23507     51/push-ecx
23508     # ecx = n
23509     8b/-> *(ebp+0xc) 1/r32/ecx
23510     # return (a->value == n)
23511     8b/-> *(ebp+8) 0/r32/eax
23512     39/compare *(eax+4) 1/r32/ecx  # Type-tree-value
23513     0f 94/set-byte-if-= %al
23514     81 4/subop/and %eax 0xff/imm32
23515 $is-simple-mu-type?:end:
23516     # . restore registers
23517     59/pop-to-ecx
23518     # . epilogue
23519     89/<- %esp 5/r32/ebp
23520     5d/pop-to-ebp
23521     c3/return
23522 
23523 is-mu-addr-type?:  # a: (addr type-tree) -> result/eax: boolean
23524     # . prologue
23525     55/push-ebp
23526     89/<- %ebp 4/r32/esp
23527     # eax = a
23528     8b/-> *(ebp+8) 0/r32/eax
23529     # if (!a->is-atom?) a = a->left
23530     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
23531     {
23532       75/jump-if-!= break/disp8
23533       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
23534     }
23535     # return (a->value == addr)
23536     81 7/subop/compare *(eax+4) 2/imm32/addr  # Type-tree-value
23537     0f 94/set-byte-if-= %al
23538     81 4/subop/and %eax 0xff/imm32
23539 $is-mu-addr-type?:end:
23540     # . epilogue
23541     89/<- %esp 5/r32/ebp
23542     5d/pop-to-ebp
23543     c3/return
23544 
23545 is-mu-array-type?:  # a: (addr type-tree) -> result/eax: boolean
23546     # . prologue
23547     55/push-ebp
23548     89/<- %ebp 4/r32/esp
23549     # eax = a
23550     8b/-> *(ebp+8) 0/r32/eax
23551     # if (!a->is-atom?) a = a->left
23552     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
23553     {
23554       75/jump-if-!= break/disp8
23555       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
23556     }
23557     # return (a->value == array)
23558     81 7/subop/compare *(eax+4) 3/imm32/array  # Type-tree-value
23559     0f 94/set-byte-if-= %al
23560     81 4/subop/and %eax 0xff/imm32
23561 $is-mu-array-type?:end:
23562     # . epilogue
23563     89/<- %esp 5/r32/ebp
23564     5d/pop-to-ebp
23565     c3/return
23566 
23567 is-mu-stream-type?:  # a: (addr type-tree) -> result/eax: boolean
23568     # . prologue
23569     55/push-ebp
23570     89/<- %ebp 4/r32/esp
23571     # eax = a
23572     8b/-> *(ebp+8) 0/r32/eax
23573     # if (!a->is-atom?) a = a->left
23574     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
23575     {
23576       75/jump-if-!= break/disp8
23577       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
23578     }
23579     # return (a->value == stream)
23580     81 7/subop/compare *(eax+4) 0xb/imm32/stream  # Type-tree-value
23581     0f 94/set-byte-if-= %al
23582     81 4/subop/and %eax 0xff/imm32
23583 $is-mu-stream-type?:end:
23584     # . epilogue
23585     89/<- %esp 5/r32/ebp
23586     5d/pop-to-ebp
23587     c3/return
23588 
23589 test-emit-subx-stmt-primitive:
23590     # Primitive operation on a variable on the stack.
23591     #   increment foo
23592     # =>
23593     #   ff 0/subop/increment *(ebp-8)
23594     #
23595     # There's a variable on the var stack as follows:
23596     #   name: 'foo'
23597     #   type: int
23598     #   stack-offset: -8
23599     #
23600     # There's a primitive with this info:
23601     #   name: 'increment'
23602     #   inouts: int/mem
23603     #   value: 'ff 0/subop/increment'
23604     #
23605     # . prologue
23606     55/push-ebp
23607     89/<- %ebp 4/r32/esp
23608     # setup
23609     (clear-stream _test-output-stream)
23610     (clear-stream $_test-output-buffered-file->buffer)
23611     # simulate allocated payloads starting with an initial fake alloc-id (0x11)
23612 $test-emit-subx-stmt-primitive:initialize-type:
23613     # var type/ecx: (payload type-tree) = int
23614     68/push 0/imm32/right:null
23615     68/push 0/imm32/right:null
23616     68/push 0/imm32/left:unused
23617     68/push 1/imm32/value:int
23618     68/push 1/imm32/is-atom?:true
23619     68/push 0x11/imm32/alloc-id:fake:payload
23620     89/<- %ecx 4/r32/esp
23621 $test-emit-subx-stmt-primitive:initialize-var:
23622     # var var-foo/ecx: (payload var) = var(type)
23623     68/push 0/imm32/no-register
23624     68/push 0/imm32/no-register
23625     68/push -8/imm32/stack-offset
23626     68/push 1/imm32/block-depth
23627     51/push-ecx/type
23628     68/push 0x11/imm32/alloc-id:fake
23629     68/push 0/imm32/name
23630     68/push 0/imm32/name
23631     68/push 0x11/imm32/alloc-id:fake:payload
23632     89/<- %ecx 4/r32/esp
23633 $test-emit-subx-stmt-primitive:initialize-var-name:
23634     # var-foo->name = "foo"
23635     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23636     (copy-array Heap "foo" %eax)
23637 $test-emit-subx-stmt-primitive:initialize-stmt-var:
23638     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
23639     68/push 0/imm32/is-deref:false
23640     68/push 0/imm32/next
23641     68/push 0/imm32/next
23642     51/push-ecx/var-foo
23643     68/push 0x11/imm32/alloc-id:fake
23644     68/push 0x11/imm32/alloc-id:fake:payload
23645     89/<- %ebx 4/r32/esp
23646 $test-emit-subx-stmt-primitive:initialize-stmt:
23647     # var stmt/esi: (addr statement)
23648     68/push 0/imm32/no-outputs
23649     68/push 0/imm32/no-outputs
23650     53/push-ebx/inouts
23651     68/push 0x11/imm32/alloc-id:fake
23652     68/push 0/imm32/operation
23653     68/push 0/imm32/operation
23654     68/push 1/imm32/tag
23655     89/<- %esi 4/r32/esp
23656 $test-emit-subx-stmt-primitive:initialize-stmt-operation:
23657     # stmt->operation = "increment"
23658     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23659     (copy-array Heap "increment" %eax)
23660 $test-emit-subx-stmt-primitive:initialize-primitive:
23661     # var primitives/ebx: (addr primitive)
23662     68/push 0/imm32/next
23663     68/push 0/imm32/next
23664     68/push 0/imm32/no-x32
23665     68/push 0/imm32/no-xm32
23666     68/push 0/imm32/no-disp32
23667     68/push 0/imm32/no-imm8
23668     68/push 0/imm32/no-imm32
23669     68/push 0/imm32/no-r32
23670     68/push 1/imm32/rm32-is-first-inout
23671     68/push 0/imm32/subx-name
23672     68/push 0/imm32/subx-name
23673     68/push 0/imm32/no-outputs
23674     68/push 0/imm32/no-outputs
23675     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
23676     68/push 0x11/imm32/alloc-id:fake
23677     68/push 0/imm32/name
23678     68/push 0/imm32/name
23679     89/<- %ebx 4/r32/esp
23680 $test-emit-subx-stmt-primitive:initialize-primitive-name:
23681     # primitives->name = "increment"
23682     (copy-array Heap "increment" %ebx)  # Primitive-name
23683 $test-emit-subx-stmt-primitive:initialize-primitive-subx-name:
23684     # primitives->subx-name = "ff 0/subop/increment"
23685     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
23686     (copy-array Heap "ff 0/subop/increment" %eax)
23687     # convert
23688     c7 0/subop/copy *Curr-block-depth 0/imm32
23689     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
23690     (flush _test-output-buffered-file)
23691 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
23697     # check output
23698     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-stmt-primitive")
23699     # . epilogue
23700     89/<- %esp 5/r32/ebp
23701     5d/pop-to-ebp
23702     c3/return
23703 
23704 test-emit-subx-stmt-primitive-register:
23705     # Primitive operation on a variable in a register.
23706     #   foo <- increment
23707     # =>
23708     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
23709     #
23710     # There's a variable on the var stack as follows:
23711     #   name: 'foo'
23712     #   type: int
23713     #   register: 'eax'
23714     #
23715     # There's a primitive with this info:
23716     #   name: 'increment'
23717     #   out: int/reg
23718     #   value: 'ff 0/subop/increment'
23719     #
23720     # . prologue
23721     55/push-ebp
23722     89/<- %ebp 4/r32/esp
23723     # setup
23724     (clear-stream _test-output-stream)
23725     (clear-stream $_test-output-buffered-file->buffer)
23726 $test-emit-subx-stmt-primitive-register:initialize-type:
23727     # var type/ecx: (payload type-tree) = int
23728     68/push 0/imm32/right:null
23729     68/push 0/imm32/right:null
23730     68/push 0/imm32/left:unused
23731     68/push 1/imm32/value:int
23732     68/push 1/imm32/is-atom?:true
23733     68/push 0x11/imm32/alloc-id:fake:payload
23734     89/<- %ecx 4/r32/esp
23735 $test-emit-subx-stmt-primitive-register:initialize-var:
23736     # var var-foo/ecx: (payload var)
23737     68/push 0/imm32/register
23738     68/push 0/imm32/register
23739     68/push 0/imm32/no-stack-offset
23740     68/push 1/imm32/block-depth
23741     51/push-ecx
23742     68/push 0x11/imm32/alloc-id:fake
23743     68/push 0/imm32/name
23744     68/push 0/imm32/name
23745     68/push 0x11/imm32/alloc-id:fake:payload
23746     89/<- %ecx 4/r32/esp
23747 $test-emit-subx-stmt-primitive-register:initialize-var-name:
23748     # var-foo->name = "foo"
23749     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23750     (copy-array Heap "foo" %eax)
23751 $test-emit-subx-stmt-primitive-register:initialize-var-register:
23752     # var-foo->register = "eax"
23753     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
23754     (copy-array Heap "eax" %eax)
23755 $test-emit-subx-stmt-primitive-register:initialize-stmt-var:
23756     # var operand/ebx: (payload stmt-var)
23757     68/push 0/imm32/is-deref:false
23758     68/push 0/imm32/next
23759     68/push 0/imm32/next
23760     51/push-ecx/var-foo
23761     68/push 0x11/imm32/alloc-id:fake
23762     68/push 0x11/imm32/alloc-id:fake:payload
23763     89/<- %ebx 4/r32/esp
23764 $test-emit-subx-stmt-primitive-register:initialize-stmt:
23765     # var stmt/esi: (addr statement)
23766     53/push-ebx/outputs
23767     68/push 0x11/imm32/alloc-id:fake
23768     68/push 0/imm32/no-inouts
23769     68/push 0/imm32/no-inouts
23770     68/push 0/imm32/operation
23771     68/push 0/imm32/operation
23772     68/push 1/imm32
23773     89/<- %esi 4/r32/esp
23774 $test-emit-subx-stmt-primitive-register:initialize-stmt-operation:
23775     # stmt->operation = "increment"
23776     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23777     (copy-array Heap "increment" %eax)
23778 $test-emit-subx-stmt-primitive-register:initialize-formal-var:
23779     # var formal-var/ebx: (payload var)
23780     68/push 0/imm32/register
23781     68/push 0/imm32/register
23782     68/push 0/imm32/no-stack-offset
23783     68/push 1/imm32/block-depth
23784     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
23785     68/push 0x11/imm32/alloc-id:fake
23786     68/push 0/imm32/name
23787     68/push 0/imm32/name
23788     68/push 0x11/imm32/alloc-id:fake:payload
23789     89/<- %ebx 4/r32/esp
23790 $test-emit-subx-stmt-primitive-register:initialize-formal-var-name:
23791     # formal-var->name = "dummy"
23792     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
23793     (copy-array Heap "dummy" %eax)
23794 $test-emit-subx-stmt-primitive-register:initialize-formal-register:
23795     # formal-var->register = "*"
23796     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
23797     (copy-array Heap "*" %eax)  # Any-register
23798 $test-emit-subx-stmt-primitive-register:initialize-var-list:
23799     # var formal-outputs/ebx: (payload list var)
23800     68/push 0/imm32/next
23801     68/push 0/imm32/next
23802     53/push-ebx/formal-var
23803     68/push 0x11/imm32/alloc-id:fake
23804     68/push 0x11/imm32/alloc-id:fake:payload
23805     89/<- %ebx 4/r32/esp
23806 $test-emit-subx-stmt-primitive-register:initialize-primitive:
23807     # var primitives/ebx: (addr primitive)
23808     68/push 0/imm32/next
23809     68/push 0/imm32/next
23810     68/push 0/imm32/no-x32
23811     68/push 0/imm32/no-xm32
23812     68/push 0/imm32/no-disp32
23813     68/push 0/imm32/no-imm8
23814     68/push 0/imm32/no-imm32
23815     68/push 0/imm32/no-r32
23816     68/push 3/imm32/rm32-is-first-output
23817     68/push 0/imm32/subx-name
23818     68/push 0/imm32/subx-name
23819     53/push-ebx/outputs
23820     68/push 0x11/imm32/alloc-id:fake
23821     68/push 0/imm32/no-inouts
23822     68/push 0/imm32/no-inouts
23823     68/push 0/imm32/name
23824     68/push 0/imm32/name
23825     89/<- %ebx 4/r32/esp
23826 $test-emit-subx-stmt-primitive-register:initialize-primitive-name:
23827     # primitives->name = "increment"
23828     (copy-array Heap "increment" %ebx)  # Primitive-name
23829 $test-emit-subx-stmt-primitive-register:initialize-primitive-subx-name:
23830     # primitives->subx-name = "ff 0/subop/increment"
23831     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
23832     (copy-array Heap "ff 0/subop/increment" %eax)
23833     # convert
23834     c7 0/subop/copy *Curr-block-depth 0/imm32
23835     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
23836     (flush _test-output-buffered-file)
23837 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
23843     # check output
23844     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-primitive-register")
23845     # . epilogue
23846     89/<- %esp 5/r32/ebp
23847     5d/pop-to-ebp
23848     c3/return
23849 
23850 test-emit-subx-stmt-select-primitive:
23851     # Select the right primitive between overloads.
23852     #   foo <- increment
23853     # =>
23854     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
23855     #
23856     # There's a variable on the var stack as follows:
23857     #   name: 'foo'
23858     #   type: int
23859     #   register: 'eax'
23860     #
23861     # There's two primitives, as follows:
23862     #   - name: 'increment'
23863     #     out: int/reg
23864     #     value: 'ff 0/subop/increment'
23865     #   - name: 'increment'
23866     #     inout: int/mem
23867     #     value: 'ff 0/subop/increment'
23868     #
23869     # . prologue
23870     55/push-ebp
23871     89/<- %ebp 4/r32/esp
23872     # setup
23873     (clear-stream _test-output-stream)
23874     (clear-stream $_test-output-buffered-file->buffer)
23875 $test-emit-subx-stmt-select-primitive:initialize-type:
23876     # var type/ecx: (payload type-tree) = int
23877     68/push 0/imm32/right:null
23878     68/push 0/imm32/right:null
23879     68/push 0/imm32/left:unused
23880     68/push 1/imm32/value:int
23881     68/push 1/imm32/is-atom?:true
23882     68/push 0x11/imm32/alloc-id:fake:payload
23883     89/<- %ecx 4/r32/esp
23884 $test-emit-subx-stmt-select-primitive:initialize-var:
23885     # var var-foo/ecx: (payload var)
23886     68/push 0/imm32/register
23887     68/push 0/imm32/register
23888     68/push 0/imm32/no-stack-offset
23889     68/push 1/imm32/block-depth
23890     51/push-ecx
23891     68/push 0x11/imm32/alloc-id:fake
23892     68/push 0/imm32/name
23893     68/push 0/imm32/name
23894     68/push 0x11/imm32/alloc-id:fake:payload
23895     89/<- %ecx 4/r32/esp
23896 $test-emit-subx-stmt-select-primitive:initialize-var-name:
23897     # var-foo->name = "foo"
23898     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23899     (copy-array Heap "foo" %eax)
23900 $test-emit-subx-stmt-select-primitive:initialize-var-register:
23901     # var-foo->register = "eax"
23902     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
23903     (copy-array Heap "eax" %eax)
23904 $test-emit-subx-stmt-select-primitive:initialize-stmt-var:
23905     # var operand/ebx: (payload stmt-var)
23906     68/push 0/imm32/is-deref:false
23907     68/push 0/imm32/next
23908     68/push 0/imm32/next
23909     51/push-ecx/var-foo
23910     68/push 0x11/imm32/alloc-id:fake
23911     68/push 0x11/imm32/alloc-id:fake:payload
23912     89/<- %ebx 4/r32/esp
23913 $test-emit-subx-stmt-select-primitive:initialize-stmt:
23914     # var stmt/esi: (addr statement)
23915     53/push-ebx/outputs
23916     68/push 0x11/imm32/alloc-id:fake
23917     68/push 0/imm32/no-inouts
23918     68/push 0/imm32/no-inouts
23919     68/push 0/imm32/operation
23920     68/push 0/imm32/operation
23921     68/push 1/imm32
23922     89/<- %esi 4/r32/esp
23923 $test-emit-subx-stmt-select-primitive:initialize-stmt-operation:
23924     # stmt->operation = "increment"
23925     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23926     (copy-array Heap "increment" %eax)
23927 $test-emit-subx-stmt-select-primitive:initialize-formal-var:
23928     # var formal-var/ebx: (payload var)
23929     68/push 0/imm32/register
23930     68/push 0/imm32/register
23931     68/push 0/imm32/no-stack-offset
23932     68/push 1/imm32/block-depth
23933     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
23934     68/push 0x11/imm32/alloc-id:fake
23935     68/push 0/imm32/name
23936     68/push 0/imm32/name
23937     68/push 0x11/imm32/alloc-id:fake:payload
23938     89/<- %ebx 4/r32/esp
23939 $test-emit-subx-stmt-select-primitive:initialize-formal-var-name:
23940     # formal-var->name = "dummy"
23941     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
23942     (copy-array Heap "dummy" %eax)
23943 $test-emit-subx-stmt-select-primitive:initialize-formal-register:
23944     # formal-var->register = "*"
23945     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
23946     (copy-array Heap "*" %eax)  # Any-register
23947 $test-emit-subx-stmt-select-primitive:initialize-var-list:
23948     # var formal-outputs/ebx: (payload list var)
23949     68/push 0/imm32/next
23950     68/push 0/imm32/next
23951     53/push-ebx/formal-var
23952     68/push 0x11/imm32/alloc-id:fake
23953     68/push 0x11/imm32/alloc-id:fake:payload
23954     89/<- %ebx 4/r32/esp
23955 $test-emit-subx-stmt-select-primitive:initialize-primitive2:
23956     # var primitive2/edi: (payload primitive)
23957     68/push 0/imm32/next
23958     68/push 0/imm32/next
23959     68/push 0/imm32/no-x32
23960     68/push 0/imm32/no-xm32
23961     68/push 0/imm32/no-disp32
23962     68/push 0/imm32/no-imm8
23963     68/push 0/imm32/no-imm32
23964     68/push 0/imm32/no-r32
23965     68/push 3/imm32/rm32-is-first-output
23966     68/push 0/imm32/subx-name
23967     68/push 0/imm32/subx-name
23968     53/push-ebx/outputs
23969     68/push 0x11/imm32/alloc-id:fake
23970     68/push 0/imm32/no-inouts
23971     68/push 0/imm32/no-inouts
23972     68/push 0/imm32/name
23973     68/push 0/imm32/name
23974     68/push 0x11/imm32/alloc-id:fake:payload
23975     89/<- %edi 4/r32/esp
23976 $test-emit-subx-stmt-select-primitive:initialize-primitive2-name:
23977     # primitives->name = "increment"
23978     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
23979     (copy-array Heap "increment" %eax)
23980 $test-emit-subx-stmt-select-primitive:initialize-primitive2-subx-name:
23981     # primitives->subx-name = "ff 0/subop/increment"
23982     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
23983     (copy-array Heap "ff 0/subop/increment" %eax)
23984 $test-emit-subx-stmt-select-primitive:initialize-primitive:
23985     # var primitives/ebx: (addr primitive)
23986     57/push-edi
23987     68/push 0x11/imm32/alloc-id:fake
23988     68/push 0/imm32/no-x32
23989     68/push 0/imm32/no-xm32
23990     68/push 0/imm32/no-disp32
23991     68/push 0/imm32/no-imm8
23992     68/push 0/imm32/no-imm32
23993     68/push 0/imm32/no-r32
23994     68/push 1/imm32/rm32-is-first-inout
23995     68/push 0/imm32/subx-name
23996     68/push 0/imm32/subx-name
23997     68/push 0/imm32/no-outputs
23998     68/push 0/imm32/no-outputs
23999     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
24000     68/push 0x11/imm32/alloc-id:fake
24001     68/push 0/imm32/name
24002     68/push 0/imm32/name
24003     89/<- %ebx 4/r32/esp
24004 $test-emit-subx-stmt-select-primitive:initialize-primitive-name:
24005     # primitives->name = "increment"
24006     (copy-array Heap "increment" %ebx)  # Primitive-name
24007 $test-emit-subx-stmt-select-primitive:initialize-primitive-subx-name:
24008     # primitives->subx-name = "ff 0/subop/increment"
24009     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
24010     (copy-array Heap "ff 0/subop/increment" %eax)
24011     # convert
24012     c7 0/subop/copy *Curr-block-depth 0/imm32
24013     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
24014     (flush _test-output-buffered-file)
24015 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
24021     # check output
24022     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive")
24023     # . epilogue
24024     89/<- %esp 5/r32/ebp
24025     5d/pop-to-ebp
24026     c3/return
24027 
24028 test-emit-subx-stmt-select-primitive-2:
24029     # Select the right primitive between overloads.
24030     #   increment foo
24031     # =>
24032     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
24033     #
24034     # There's a variable on the var stack as follows:
24035     #   name: 'foo'
24036     #   type: int
24037     #   register: 'eax'
24038     #
24039     # There's two primitives, as follows:
24040     #   - name: 'increment'
24041     #     out: int/reg
24042     #     value: 'ff 0/subop/increment'
24043     #   - name: 'increment'
24044     #     inout: int/mem
24045     #     value: 'ff 0/subop/increment'
24046     #
24047     # . prologue
24048     55/push-ebp
24049     89/<- %ebp 4/r32/esp
24050     # setup
24051     (clear-stream _test-output-stream)
24052     (clear-stream $_test-output-buffered-file->buffer)
24053 $test-emit-subx-stmt-select-primitive-2:initialize-type:
24054     # var type/ecx: (payload type-tree) = int
24055     68/push 0/imm32/right:null
24056     68/push 0/imm32/right:null
24057     68/push 0/imm32/left:unused
24058     68/push 1/imm32/value:int
24059     68/push 1/imm32/is-atom?:true
24060     68/push 0x11/imm32/alloc-id:fake:payload
24061     89/<- %ecx 4/r32/esp
24062 $test-emit-subx-stmt-select-primitive-2:initialize-var:
24063     # var var-foo/ecx: (payload var)
24064     68/push 0/imm32/register
24065     68/push 0/imm32/register
24066     68/push 0/imm32/no-stack-offset
24067     68/push 1/imm32/block-depth
24068     51/push-ecx
24069     68/push 0x11/imm32/alloc-id:fake
24070     68/push 0/imm32/name
24071     68/push 0/imm32/name
24072     68/push 0x11/imm32/alloc-id:fake:payload
24073     89/<- %ecx 4/r32/esp
24074 $test-emit-subx-stmt-select-primitive-2:initialize-var-name:
24075     # var-foo->name = "foo"
24076     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
24077     (copy-array Heap "foo" %eax)
24078 $test-emit-subx-stmt-select-primitive-2:initialize-var-register:
24079     # var-foo->register = "eax"
24080     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
24081     (copy-array Heap "eax" %eax)
24082 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-var:
24083     # var operand/ebx: (payload stmt-var)
24084     68/push 0/imm32/is-deref:false
24085     68/push 0/imm32/next
24086     68/push 0/imm32/next
24087     51/push-ecx/var-foo
24088     68/push 0x11/imm32/alloc-id:fake
24089     68/push 0x11/imm32/alloc-id:fake:payload
24090     89/<- %ebx 4/r32/esp
24091 $test-emit-subx-stmt-select-primitive-2:initialize-stmt:
24092     # var stmt/esi: (addr statement)
24093     68/push 0/imm32/no-outputs
24094     68/push 0/imm32/no-outputs
24095     53/push-ebx/inouts
24096     68/push 0x11/imm32/alloc-id:fake
24097     68/push 0/imm32/operation
24098     68/push 0/imm32/operation
24099     68/push 1/imm32
24100     89/<- %esi 4/r32/esp
24101 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-operation:
24102     # stmt->operation = "increment"
24103     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
24104     (copy-array Heap "increment" %eax)
24105 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var:
24106     # var formal-var/ebx: (payload var)
24107     68/push 0/imm32/register
24108     68/push 0/imm32/register
24109     68/push 0/imm32/no-stack-offset
24110     68/push 1/imm32/block-depth
24111     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
24112     68/push 0x11/imm32/alloc-id:fake
24113     68/push 0/imm32/name
24114     68/push 0/imm32/name
24115     68/push 0x11/imm32/alloc-id:fake:payload
24116     89/<- %ebx 4/r32/esp
24117 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var-name:
24118     # formal-var->name = "dummy"
24119     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
24120     (copy-array Heap "dummy" %eax)
24121 $test-emit-subx-stmt-select-primitive-2:initialize-formal-register:
24122     # formal-var->register = "*"
24123     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
24124     (copy-array Heap "*" %eax)  # Any-register
24125 $test-emit-subx-stmt-select-primitive-2:initialize-var-list:
24126     # var formal-outputs/ebx: (payload list stmt-var)
24127     68/push 0/imm32/next
24128     68/push 0/imm32/next
24129     53/push-ebx/formal-var
24130     68/push 0x11/imm32/alloc-id:fake
24131     68/push 0x11/imm32/alloc-id:fake:payload
24132     89/<- %ebx 4/r32/esp
24133 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2:
24134     # var primitive2/edi: (payload primitive)
24135     68/push 0/imm32/next
24136     68/push 0/imm32/next
24137     68/push 0/imm32/no-x32
24138     68/push 0/imm32/no-xm32
24139     68/push 0/imm32/no-disp32
24140     68/push 0/imm32/no-imm8
24141     68/push 0/imm32/no-imm32
24142     68/push 0/imm32/no-r32
24143     68/push 3/imm32/rm32-is-first-output
24144     68/push 0/imm32/subx-name
24145     68/push 0/imm32/subx-name
24146     53/push-ebx/outputs
24147     68/push 0x11/imm32/alloc-id:fake
24148     68/push 0/imm32/no-inouts
24149     68/push 0/imm32/no-inouts
24150     68/push 0/imm32/name
24151     68/push 0/imm32/name
24152     68/push 0x11/imm32/alloc-id:fake:payload
24153     89/<- %edi 4/r32/esp
24154 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-name:
24155     # primitives->name = "increment"
24156     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
24157     (copy-array Heap "increment" %eax)
24158 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-subx-name:
24159     # primitives->subx-name = "ff 0/subop/increment"
24160     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
24161     (copy-array Heap "ff 0/subop/increment" %eax)
24162 $test-emit-subx-stmt-select-primitive-2:initialize-primitive:
24163     # var primitives/ebx: (addr primitive)
24164     57/push-edi
24165     68/push 0x11/imm32/alloc-id:fake
24166     68/push 0/imm32/no-x32
24167     68/push 0/imm32/no-xm32
24168     68/push 0/imm32/no-disp32
24169     68/push 0/imm32/no-imm8
24170     68/push 0/imm32/no-imm32
24171     68/push 0/imm32/no-r32
24172     68/push 1/imm32/rm32-is-first-inout
24173     68/push 0/imm32/subx-name
24174     68/push 0/imm32/subx-name
24175     68/push 0/imm32/no-outputs
24176     68/push 0/imm32/no-outputs
24177     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
24178     68/push 0x11/imm32/alloc-id:fake
24179     68/push 0/imm32/name
24180     68/push 0/imm32/name
24181     89/<- %ebx 4/r32/esp
24182 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-name:
24183     # primitives->name = "increment"
24184     (copy-array Heap "increment" %ebx)  # Primitive-name
24185 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-subx-name:
24186     # primitives->subx-name = "ff 0/subop/increment"
24187     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
24188     (copy-array Heap "ff 0/subop/increment" %eax)
24189     # convert
24190     c7 0/subop/copy *Curr-block-depth 0/imm32
24191     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
24192     (flush _test-output-buffered-file)
24193 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
24199     # check output
24200     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive-2")
24201     # . epilogue
24202     89/<- %esp 5/r32/ebp
24203     5d/pop-to-ebp
24204     c3/return
24205 
24206 test-increment-register:
24207     # Select the right register between overloads.
24208     #   foo <- increment
24209     # =>
24210     #   50/increment-eax
24211     #
24212     # There's a variable on the var stack as follows:
24213     #   name: 'foo'
24214     #   type: int
24215     #   register: 'eax'
24216     #
24217     # Primitives are the global definitions.
24218     #
24219     # . prologue
24220     55/push-ebp
24221     89/<- %ebp 4/r32/esp
24222     # setup
24223     (clear-stream _test-output-stream)
24224     (clear-stream $_test-output-buffered-file->buffer)
24225 $test-increment-register:initialize-type:
24226     # var type/ecx: (payload type-tree) = int
24227     68/push 0/imm32/right:null
24228     68/push 0/imm32/right:null
24229     68/push 0/imm32/left:unused
24230     68/push 1/imm32/value:int
24231     68/push 1/imm32/is-atom?:true
24232     68/push 0x11/imm32/alloc-id:fake:payload
24233     89/<- %ecx 4/r32/esp
24234 $test-increment-register:initialize-var:
24235     # var var-foo/ecx: (payload var)
24236     68/push 0/imm32/register
24237     68/push 0/imm32/register
24238     68/push 0/imm32/no-stack-offset
24239     68/push 1/imm32/block-depth
24240     51/push-ecx
24241     68/push 0x11/imm32/alloc-id:fake
24242     68/push 0/imm32/name
24243     68/push 0/imm32/name
24244     68/push 0x11/imm32/alloc-id:fake:payload
24245     89/<- %ecx 4/r32/esp
24246 $test-increment-register:initialize-var-name:
24247     # var-foo->name = "foo"
24248     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
24249     (copy-array Heap "foo" %eax)
24250 $test-increment-register:initialize-var-register:
24251     # var-foo->register = "eax"
24252     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
24253     (copy-array Heap "eax" %eax)
24254 $test-increment-register:initialize-stmt-var:
24255     # var operand/ebx: (payload stmt-var)
24256     68/push 0/imm32/is-deref:false
24257     68/push 0/imm32/next
24258     68/push 0/imm32/next
24259     51/push-ecx/var-foo
24260     68/push 0x11/imm32/alloc-id:fake
24261     68/push 0x11/imm32/alloc-id:fake:payload
24262     89/<- %ebx 4/r32/esp
24263 $test-increment-register:initialize-stmt:
24264     # var stmt/esi: (addr statement)
24265     53/push-ebx/outputs
24266     68/push 0x11/imm32/alloc-id:fake
24267     68/push 0/imm32/no-inouts
24268     68/push 0/imm32/no-inouts
24269     68/push 0/imm32/operation
24270     68/push 0/imm32/operation
24271     68/push 1/imm32
24272     89/<- %esi 4/r32/esp
24273 $test-increment-register:initialize-stmt-operation:
24274     # stmt->operation = "increment"
24275     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
24276     (copy-array Heap "increment" %eax)
24277     # convert
24278     c7 0/subop/copy *Curr-block-depth 0/imm32
24279     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
24280     (flush _test-output-buffered-file)
24281 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
24287     # check output
24288     (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register")
24289     # . epilogue
24290     89/<- %esp 5/r32/ebp
24291     5d/pop-to-ebp
24292     c3/return
24293 
24294 test-add-reg-to-reg:
24295     #   var1/reg <- add var2/reg
24296     # =>
24297     #   01/add-to %var1 var2
24298     #
24299     # . prologue
24300     55/push-ebp
24301     89/<- %ebp 4/r32/esp
24302     # setup
24303     (clear-stream _test-output-stream)
24304     (clear-stream $_test-output-buffered-file->buffer)
24305 $test-add-reg-to-reg:initialize-type:
24306     # var type/ecx: (payload type-tree) = int
24307     68/push 0/imm32/right:null
24308     68/push 0/imm32/right:null
24309     68/push 0/imm32/left:unused
24310     68/push 1/imm32/value:int
24311     68/push 1/imm32/is-atom?:true
24312     68/push 0x11/imm32/alloc-id:fake:payload
24313     89/<- %ecx 4/r32/esp
24314 $test-add-reg-to-reg:initialize-var1:
24315     # var var1/ecx: (payload var)
24316     68/push 0/imm32/register
24317     68/push 0/imm32/register
24318     68/push 0/imm32/no-stack-offset
24319     68/push 1/imm32/block-depth
24320     51/push-ecx
24321     68/push 0x11/imm32/alloc-id:fake
24322     68/push 0/imm32/name
24323     68/push 0/imm32/name
24324     68/push 0x11/imm32/alloc-id:fake:payload
24325     89/<- %ecx 4/r32/esp
24326 $test-add-reg-to-reg:initialize-var1-name:
24327     # var1->name = "var1"
24328     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
24329     (copy-array Heap "var1" %eax)
24330 $test-add-reg-to-reg:initialize-var1-register:
24331     # var1->register = "eax"
24332     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
24333     (copy-array Heap "eax" %eax)
24334 $test-add-reg-to-reg:initialize-var2:
24335     # var var2/edx: (payload var)
24336     68/push 0/imm32/register
24337     68/push 0/imm32/register
24338     68/push 0/imm32/no-stack-offset
24339     68/push 1/imm32/block-depth
24340     ff 6/subop/push *(ecx+0x10)
24341     68/push 0x11/imm32/alloc-id:fake
24342     68/push 0/imm32/name
24343     68/push 0/imm32/name
24344     68/push 0x11/imm32/alloc-id:fake:payload
24345     89/<- %edx 4/r32/esp
24346 $test-add-reg-to-reg:initialize-var2-name:
24347     # var2->name = "var2"
24348     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
24349     (copy-array Heap "var2" %eax)
24350 $test-add-reg-to-reg:initialize-var2-register:
24351     # var2->register = "ecx"
24352     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
24353     (copy-array Heap "ecx" %eax)
24354 $test-add-reg-to-reg:initialize-inouts:
24355     # var inouts/esi: (payload stmt-var) = [var2]
24356     68/push 0/imm32/is-deref:false
24357     68/push 0/imm32/next
24358     68/push 0/imm32/next
24359     52/push-edx/var2
24360     68/push 0x11/imm32/alloc-id:fake
24361     68/push 0x11/imm32/alloc-id:fake:payload
24362     89/<- %esi 4/r32/esp
24363 $test-add-reg-to-reg:initialize-outputs:
24364     # var outputs/edi: (payload stmt-var) = [var1]
24365     68/push 0/imm32/is-deref:false
24366     68/push 0/imm32/next
24367     68/push 0/imm32/next
24368     51/push-ecx/var1
24369     68/push 0x11/imm32/alloc-id:fake
24370     68/push 0x11/imm32/alloc-id:fake:payload
24371     89/<- %edi 4/r32/esp
24372 $test-add-reg-to-reg:initialize-stmt:
24373     # var stmt/esi: (addr statement)
24374     68/push 0/imm32/next
24375     68/push 0/imm32/next
24376     57/push-edi/outputs
24377     68/push 0x11/imm32/alloc-id:fake
24378     56/push-esi/inouts
24379     68/push 0x11/imm32/alloc-id:fake
24380     68/push 0/imm32/operation
24381     68/push 0/imm32/operation
24382     68/push 1/imm32/tag:stmt1
24383     89/<- %esi 4/r32/esp
24384 $test-add-reg-to-reg:initialize-stmt-operation:
24385     # stmt->operation = "add"
24386     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
24387     (copy-array Heap "add" %eax)
24388     # convert
24389     c7 0/subop/copy *Curr-block-depth 0/imm32
24390     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
24391     (flush _test-output-buffered-file)
24392 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
24398     # check output
24399     (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg")
24400     # . epilogue
24401     89/<- %esp 5/r32/ebp
24402     5d/pop-to-ebp
24403     c3/return
24404 
24405 test-add-reg-to-mem:
24406     #   add-to var1 var2/reg
24407     # =>
24408     #   01/add-to *(ebp+__) var2
24409     #
24410     # . prologue
24411     55/push-ebp
24412     89/<- %ebp 4/r32/esp
24413     # setup
24414     (clear-stream _test-output-stream)
24415     (clear-stream $_test-output-buffered-file->buffer)
24416 $test-add-reg-to-mem:initialize-type:
24417     # var type/ecx: (payload type-tree) = int
24418     68/push 0/imm32/right:null
24419     68/push 0/imm32/right:null
24420     68/push 0/imm32/left:unused
24421     68/push 1/imm32/value:int
24422     68/push 1/imm32/is-atom?:true
24423     68/push 0x11/imm32/alloc-id:fake:payload
24424     89/<- %ecx 4/r32/esp
24425 $test-add-reg-to-mem:initialize-var1:
24426     # var var1/ecx: (payload var)
24427     68/push 0/imm32/register
24428     68/push 0/imm32/register
24429     68/push 8/imm32/stack-offset
24430     68/push 1/imm32/block-depth
24431     51/push-ecx
24432     68/push 0x11/imm32/alloc-id:fake
24433     68/push 0/imm32/name
24434     68/push 0/imm32/name
24435     68/push 0x11/imm32/alloc-id:fake:payload
24436     89/<- %ecx 4/r32/esp
24437 $test-add-reg-to-mem:initialize-var1-name:
24438     # var1->name = "var1"
24439     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
24440     (copy-array Heap "var1" %eax)
24441 $test-add-reg-to-mem:initialize-var2:
24442     # var var2/edx: (payload var)
24443     68/push 0/imm32/register
24444     68/push 0/imm32/register
24445     68/push 0/imm32/no-stack-offset
24446     68/push 1/imm32/block-depth
24447     ff 6/subop/push *(ecx+0x10)
24448     68/push 0x11/imm32/alloc-id:fake
24449     68/push 0/imm32/name
24450     68/push 0/imm32/name
24451     68/push 0x11/imm32/alloc-id:fake:payload
24452     89/<- %edx 4/r32/esp
24453 $test-add-reg-to-mem:initialize-var2-name:
24454     # var2->name = "var2"
24455     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
24456     (copy-array Heap "var2" %eax)
24457 $test-add-reg-to-mem:initialize-var2-register:
24458     # var2->register = "ecx"
24459     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
24460     (copy-array Heap "ecx" %eax)
24461 $test-add-reg-to-mem:initialize-inouts:
24462     # var inouts/esi: (payload stmt-var) = [var2]
24463     68/push 0/imm32/is-deref:false
24464     68/push 0/imm32/next
24465     68/push 0/imm32/next
24466     52/push-edx/var2
24467     68/push 0x11/imm32/alloc-id:fake
24468     68/push 0x11/imm32/alloc-id:fake:payload
24469     89/<- %esi 4/r32/esp
24470     # inouts = [var1, var2]
24471     68/push 0/imm32/is-deref:false
24472     56/push-esi/next
24473     68/push 0x11/imm32/alloc-id:fake
24474     51/push-ecx/var1
24475     68/push 0x11/imm32/alloc-id:fake
24476     68/push 0x11/imm32/alloc-id:fake:payload
24477     89/<- %esi 4/r32/esp
24478 $test-add-reg-to-mem:initialize-stmt:
24479     # var stmt/esi: (addr statement)
24480     68/push 0/imm32/next
24481     68/push 0/imm32/next
24482     68/push 0/imm32/outputs
24483     68/push 0/imm32/outputs
24484     56/push-esi/inouts
24485     68/push 0x11/imm32/alloc-id:fake
24486     68/push 0/imm32/operation
24487     68/push 0/imm32/operation
24488     68/push 1/imm32/tag:stmt1
24489     89/<- %esi 4/r32/esp
24490 $test-add-reg-to-mem:initialize-stmt-operation:
24491     # stmt->operation = "add-to"
24492     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
24493     (copy-array Heap "add-to" %eax)
24494     # convert
24495     c7 0/subop/copy *Curr-block-depth 0/imm32
24496     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
24497     (flush _test-output-buffered-file)
24498 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
24504     # check output
24505     (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem")
24506     # . epilogue
24507     89/<- %esp 5/r32/ebp
24508     5d/pop-to-ebp
24509     c3/return
24510 
24511 test-add-mem-to-reg:
24512     #   var1/reg <- add var2
24513     # =>
24514     #   03/add *(ebp+__) var1
24515     #
24516     # . prologue
24517     55/push-ebp
24518     89/<- %ebp 4/r32/esp
24519     # setup
24520     (clear-stream _test-output-stream)
24521     (clear-stream $_test-output-buffered-file->buffer)
24522 $test-add-mem-to-reg:initialize-type:
24523     # var type/ecx: (payload type-tree) = int
24524     68/push 0/imm32/right:null
24525     68/push 0/imm32/right:null
24526     68/push 0/imm32/left:unused
24527     68/push 1/imm32/value:int
24528     68/push 1/imm32/is-atom?:true
24529     68/push 0x11/imm32/alloc-id:fake:payload
24530     89/<- %ecx 4/r32/esp
24531 $test-add-mem-to-reg:initialize-var:
24532     # var var1/ecx: (payload var)
24533     68/push 0/imm32/register
24534     68/push 0/imm32/register
24535     68/push 0/imm32/no-stack-offset
24536     68/push 1/imm32/block-depth
24537     51/push-ecx
24538     68/push 0x11/imm32/alloc-id:fake
24539     68/push 0/imm32/name
24540     68/push 0/imm32/name
24541     68/push 0x11/imm32/alloc-id:fake:payload
24542     89/<- %ecx 4/r32/esp
24543 $test-add-mem-to-reg:initialize-var-name:
24544     # var1->name = "foo"
24545     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
24546     (copy-array Heap "var1" %eax)
24547 $test-add-mem-to-reg:initialize-var-register:
24548     # var1->register = "eax"
24549     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
24550     (copy-array Heap "eax" %eax)
24551 $test-add-mem-to-reg:initialize-var2:
24552     # var var2/edx: (payload var)
24553     68/push 0/imm32/register
24554     68/push 0/imm32/register
24555     68/push 8/imm32/stack-offset
24556     68/push 1/imm32/block-depth
24557     ff 6/subop/push *(ecx+0x10)
24558     68/push 0x11/imm32/alloc-id:fake
24559     68/push 0/imm32/name
24560     68/push 0/imm32/name
24561     68/push 0x11/imm32/alloc-id:fake:payload
24562     89/<- %edx 4/r32/esp
24563 $test-add-mem-to-reg:initialize-var2-name:
24564     # var2->name = "var2"
24565     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
24566     (copy-array Heap "var2" %eax)
24567 $test-add-mem-to-reg:initialize-inouts:
24568     # var inouts/esi: (payload stmt-var) = [var2]
24569     68/push 0/imm32/is-deref:false
24570     68/push 0/imm32/next
24571     68/push 0/imm32/next
24572     52/push-edx/var2
24573     68/push 0x11/imm32/alloc-id:fake
24574     68/push 0x11/imm32/alloc-id:fake:payload
24575     89/<- %esi 4/r32/esp
24576 $test-add-mem-to-reg:initialize-outputs:
24577     # var outputs/edi: (payload stmt-var) = [var1]
24578     68/push 0/imm32/is-deref:false
24579     68/push 0/imm32/next
24580     68/push 0/imm32/next
24581     51/push-ecx/var1
24582     68/push 0x11/imm32/alloc-id:fake
24583     68/push 0x11/imm32/alloc-id:fake:payload
24584     89/<- %edi 4/r32/esp
24585 $test-add-mem-to-reg:initialize-stmt:
24586     # var stmt/esi: (addr statement)
24587     68/push 0/imm32/next
24588     68/push 0/imm32/next
24589     57/push-edi/outputs
24590     68/push 0x11/imm32/alloc-id:fake
24591     56/push-esi/inouts
24592     68/push 0x11/imm32/alloc-id:fake
24593     68/push 0/imm32/operation
24594     68/push 0/imm32/operation
24595     68/push 1/imm32/tag:stmt1
24596     89/<- %esi 4/r32/esp
24597 $test-add-mem-to-reg:initialize-stmt-operation:
24598     # stmt->operation = "add"
24599     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
24600     (copy-array Heap "add" %eax)
24601     # convert
24602     c7 0/subop/copy *Curr-block-depth 0/imm32
24603     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
24604     (flush _test-output-buffered-file)
24605 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
24611     # check output
24612     (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg")
24613     # . epilogue
24614     89/<- %esp 5/r32/ebp
24615     5d/pop-to-ebp
24616     c3/return
24617 
24618 test-add-literal-to-eax:
24619     #   var1/eax <- add 0x34
24620     # =>
24621     #   05/add-to-eax 0x34/imm32
24622     #
24623     # . prologue
24624     55/push-ebp
24625     89/<- %ebp 4/r32/esp
24626     # setup
24627     (clear-stream _test-output-stream)
24628     (clear-stream $_test-output-buffered-file->buffer)
24629 $test-add-literal-to-eax:initialize-var-type:
24630     # var type/ecx: (payload type-tree) = int
24631     68/push 0/imm32/right:null
24632     68/push 0/imm32/right:null
24633     68/push 0/imm32/left:unused
24634     68/push 1/imm32/value:int
24635     68/push 1/imm32/is-atom?:true
24636     68/push 0x11/imm32/alloc-id:fake:payload
24637     89/<- %ecx 4/r32/esp
24638 $test-add-literal-to-eax:initialize-var:
24639     # var v/ecx: (payload var)
24640     68/push 0/imm32/register
24641     68/push 0/imm32/register
24642     68/push 0/imm32/no-stack-offset
24643     68/push 1/imm32/block-depth
24644     51/push-ecx
24645     68/push 0x11/imm32/alloc-id:fake
24646     68/push 0/imm32/name
24647     68/push 0/imm32/name
24648     68/push 0x11/imm32/alloc-id:fake:payload
24649     89/<- %ecx 4/r32/esp
24650 $test-add-literal-to-eax:initialize-var-name:
24651     # v->name = "v"
24652     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
24653     (copy-array Heap "v" %eax)
24654 $test-add-literal-to-eax:initialize-var-register:
24655     # v->register = "eax"
24656     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
24657     (copy-array Heap "eax" %eax)
24658 $test-add-literal-to-eax:initialize-literal-type:
24659     # var type/edx: (payload type-tree) = literal
24660     68/push 0/imm32/right:null
24661     68/push 0/imm32/right:null
24662     68/push 0/imm32/left:unused
24663     68/push 0/imm32/value:literal
24664     68/push 1/imm32/is-atom?:true
24665     68/push 0x11/imm32/alloc-id:fake:payload
24666     89/<- %edx 4/r32/esp
24667 $test-add-literal-to-eax:initialize-literal:
24668     # var l/edx: (payload var)
24669     68/push 0/imm32/register
24670     68/push 0/imm32/register
24671     68/push 0/imm32/no-stack-offset
24672     68/push 1/imm32/block-depth
24673     52/push-edx
24674     68/push 0x11/imm32/alloc-id:fake
24675     68/push 0/imm32/name
24676     68/push 0/imm32/name
24677     68/push 0x11/imm32/alloc-id:fake:payload
24678     89/<- %edx 4/r32/esp
24679 $test-add-literal-to-eax:initialize-literal-value:
24680     # l->name = "0x34"
24681     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
24682     (copy-array Heap "0x34" %eax)
24683 $test-add-literal-to-eax:initialize-inouts:
24684     # var inouts/esi: (payload stmt-var) = [l]
24685     68/push 0/imm32/is-deref:false
24686     68/push 0/imm32/next
24687     68/push 0/imm32/next
24688     52/push-edx/l
24689     68/push 0x11/imm32/alloc-id:fake
24690     68/push 0x11/imm32/alloc-id:fake:payload
24691     89/<- %esi 4/r32/esp
24692 $test-add-literal-to-eax:initialize-outputs:
24693     # var outputs/edi: (payload stmt-var) = [v]
24694     68/push 0/imm32/is-deref:false
24695     68/push 0/imm32/next
24696     68/push 0/imm32/next
24697     51/push-ecx/v
24698     68/push 0x11/imm32/alloc-id:fake
24699     68/push 0x11/imm32/alloc-id:fake:payload
24700     89/<- %edi 4/r32/esp
24701 $test-add-literal-to-eax:initialize-stmt:
24702     # var stmt/esi: (addr statement)
24703     68/push 0/imm32/next
24704     68/push 0/imm32/next
24705     57/push-edi/outputs
24706     68/push 0x11/imm32/alloc-id:fake
24707     56/push-esi/inouts
24708     68/push 0x11/imm32/alloc-id:fake
24709     68/push 0/imm32/operation
24710     68/push 0/imm32/operation
24711     68/push 1/imm32/tag:stmt1
24712     89/<- %esi 4/r32/esp
24713 $test-add-literal-to-eax:initialize-stmt-operation:
24714     # stmt->operation = "add"
24715     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
24716     (copy-array Heap "add" %eax)
24717     # convert
24718     c7 0/subop/copy *Curr-block-depth 0/imm32
24719     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
24720     (flush _test-output-buffered-file)
24721 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
24727     # check output
24728     (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax")
24729     # . epilogue
24730     89/<- %esp 5/r32/ebp
24731     5d/pop-to-ebp
24732     c3/return
24733 
24734 test-add-literal-to-reg:
24735     #   var1/ecx <- add 0x34
24736     # =>
24737     #   81 0/subop/add %ecx 0x34/imm32
24738     #
24739     # . prologue
24740     55/push-ebp
24741     89/<- %ebp 4/r32/esp
24742     # setup
24743     (clear-stream _test-output-stream)
24744     (clear-stream $_test-output-buffered-file->buffer)
24745 $test-add-literal-to-reg:initialize-var-type:
24746     # var type/ecx: (payload type-tree) = int
24747     68/push 0/imm32/right:null
24748     68/push 0/imm32/right:null
24749     68/push 0/imm32/left:unused
24750     68/push 1/imm32/value:int
24751     68/push 1/imm32/is-atom?:true
24752     68/push 0x11/imm32/alloc-id:fake:payload
24753     89/<- %ecx 4/r32/esp
24754 $test-add-literal-to-reg:initialize-var:
24755     # var v/ecx: (payload var)
24756     68/push 0/imm32/register
24757     68/push 0/imm32/register
24758     68/push 0/imm32/no-stack-offset
24759     68/push 1/imm32/block-depth
24760     51/push-ecx
24761     68/push 0x11/imm32/alloc-id:fake
24762     68/push 0/imm32/name
24763     68/push 0/imm32/name
24764     68/push 0x11/imm32/alloc-id:fake:payload
24765     89/<- %ecx 4/r32/esp
24766 $test-add-literal-to-reg:initialize-var-name:
24767     # v->name = "v"
24768     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
24769     (copy-array Heap "v" %eax)
24770 $test-add-literal-to-reg:initialize-var-register:
24771     # v->register = "ecx"
24772     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
24773     (copy-array Heap "ecx" %eax)
24774 $test-add-literal-to-reg:initialize-literal-type:
24775     # var type/edx: (payload type-tree) = literal
24776     68/push 0/imm32/right:null
24777     68/push 0/imm32/right:null
24778     68/push 0/imm32/left:unused
24779     68/push 0/imm32/value:literal
24780     68/push 1/imm32/is-atom?:true
24781     68/push 0x11/imm32/alloc-id:fake:payload
24782     89/<- %edx 4/r32/esp
24783 $test-add-literal-to-reg:initialize-literal:
24784     # var l/edx: (payload var)
24785     68/push 0/imm32/register
24786     68/push 0/imm32/register
24787     68/push 0/imm32/no-stack-offset
24788     68/push 1/imm32/block-depth
24789     52/push-edx
24790     68/push 0x11/imm32/alloc-id:fake
24791     68/push 0/imm32/name
24792     68/push 0/imm32/name
24793     68/push 0x11/imm32/alloc-id:fake:payload
24794     89/<- %edx 4/r32/esp
24795 $test-add-literal-to-reg:initialize-literal-value:
24796     # l->name = "0x34"
24797     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
24798     (copy-array Heap "0x34" %eax)
24799 $test-add-literal-to-reg:initialize-inouts:
24800     # var inouts/esi: (payload stmt-var) = [l]
24801     68/push 0/imm32/is-deref:false
24802     68/push 0/imm32/next
24803     68/push 0/imm32/next
24804     52/push-edx/l
24805     68/push 0x11/imm32/alloc-id:fake
24806     68/push 0x11/imm32/alloc-id:fake:payload
24807     89/<- %esi 4/r32/esp
24808 $test-add-literal-to-reg:initialize-outputs:
24809     # var outputs/edi: (payload stmt-var) = [v]
24810     68/push 0/imm32/is-deref:false
24811     68/push 0/imm32/next
24812     68/push 0/imm32/next
24813     51/push-ecx/v
24814     68/push 0x11/imm32/alloc-id:fake
24815     68/push 0x11/imm32/alloc-id:fake:payload
24816     89/<- %edi 4/r32/esp
24817 $test-add-literal-to-reg:initialize-stmt:
24818     # var stmt/esi: (addr statement)
24819     68/push 0/imm32/next
24820     68/push 0/imm32/next
24821     57/push-edi/outputs
24822     68/push 0x11/imm32/alloc-id:fake
24823     56/push-esi/inouts
24824     68/push 0x11/imm32/alloc-id:fake
24825     68/push 0/imm32/operation
24826     68/push 0/imm32/operation
24827     68/push 1/imm32/tag:stmt1
24828     89/<- %esi 4/r32/esp
24829 $test-add-literal-to-reg:initialize-stmt-operation:
24830     # stmt->operation = "add"
24831     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
24832     (copy-array Heap "add" %eax)
24833     # convert
24834     c7 0/subop/copy *Curr-block-depth 0/imm32
24835     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
24836     (flush _test-output-buffered-file)
24837 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
24843     # check output
24844     (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg")
24845     # . epilogue
24846     89/<- %esp 5/r32/ebp
24847     5d/pop-to-ebp
24848     c3/return
24849 
24850 test-add-literal-to-mem:
24851     #   add-to var1, 0x34
24852     # =>
24853     #   81 0/subop/add %eax 0x34/imm32
24854     #
24855     # . prologue
24856     55/push-ebp
24857     89/<- %ebp 4/r32/esp
24858     # setup
24859     (clear-stream _test-output-stream)
24860     (clear-stream $_test-output-buffered-file->buffer)
24861 $test-add-literal-to-mem:initialize-type:
24862     # var type/ecx: (payload type-tree) = int
24863     68/push 0/imm32/right:null
24864     68/push 0/imm32/right:null
24865     68/push 0/imm32/left:unused
24866     68/push 1/imm32/value:int
24867     68/push 1/imm32/is-atom?:true
24868     68/push 0x11/imm32/alloc-id:fake:payload
24869     89/<- %ecx 4/r32/esp
24870 $test-add-literal-to-mem:initialize-var1:
24871     # var var1/ecx: (payload var)
24872     68/push 0/imm32/register
24873     68/push 0/imm32/register
24874     68/push 8/imm32/stack-offset
24875     68/push 1/imm32/block-depth
24876     51/push-ecx
24877     68/push 0x11/imm32/alloc-id:fake
24878     68/push 0/imm32/name
24879     68/push 0/imm32/name
24880     68/push 0x11/imm32/alloc-id:fake:payload
24881     89/<- %ecx 4/r32/esp
24882 $test-add-literal-to-mem:initialize-var1-name:
24883     # var1->name = "var1"
24884     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
24885     (copy-array Heap "var1" %eax)
24886 $test-add-literal-to-mem:initialize-literal-type:
24887     # var type/edx: (payload type-tree) = literal
24888     68/push 0/imm32/right:null
24889     68/push 0/imm32/right:null
24890     68/push 0/imm32/left:unused
24891     68/push 0/imm32/value:literal
24892     68/push 1/imm32/is-atom?:true
24893     68/push 0x11/imm32/alloc-id:fake:payload
24894     89/<- %edx 4/r32/esp
24895 $test-add-literal-to-mem:initialize-literal:
24896     # var l/edx: (payload var)
24897     68/push 0/imm32/register
24898     68/push 0/imm32/register
24899     68/push 0/imm32/no-stack-offset
24900     68/push 1/imm32/block-depth
24901     52/push-edx
24902     68/push 0x11/imm32/alloc-id:fake
24903     68/push 0/imm32/name
24904     68/push 0/imm32/name
24905     68/push 0x11/imm32/alloc-id:fake:payload
24906     89/<- %edx 4/r32/esp
24907 $test-add-literal-to-mem:initialize-literal-value:
24908     # l->name = "0x34"
24909     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
24910     (copy-array Heap "0x34" %eax)
24911 $test-add-literal-to-mem:initialize-inouts:
24912     # var inouts/esi: (payload stmt-var) = [l]
24913     68/push 0/imm32/is-deref:false
24914     68/push 0/imm32/next
24915     68/push 0/imm32/next
24916     52/push-edx/l
24917     68/push 0x11/imm32/alloc-id:fake
24918     68/push 0x11/imm32/alloc-id:fake:payload
24919     89/<- %esi 4/r32/esp
24920     # var inouts = (handle stmt-var) = [var1, var2]
24921     68/push 0/imm32/is-deref:false
24922     56/push-esi/next
24923     68/push 0x11/imm32/alloc-id:fake
24924     51/push-ecx/var1
24925     68/push 0x11/imm32/alloc-id:fake
24926     68/push 0x11/imm32/alloc-id:fake:payload
24927     89/<- %esi 4/r32/esp
24928 $test-add-literal-to-mem:initialize-stmt:
24929     # var stmt/esi: (addr statement)
24930     68/push 0/imm32/next
24931     68/push 0/imm32/next
24932     68/push 0/imm32/outputs
24933     68/push 0/imm32/outputs
24934     56/push-esi/inouts
24935     68/push 0x11/imm32/alloc-id:fake
24936     68/push 0/imm32/operation
24937     68/push 0/imm32/operation
24938     68/push 1/imm32/tag:stmt1
24939     89/<- %esi 4/r32/esp
24940 $test-add-literal-to-mem:initialize-stmt-operation:
24941     # stmt->operation = "add-to"
24942     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
24943     (copy-array Heap "add-to" %eax)
24944     # convert
24945     c7 0/subop/copy *Curr-block-depth 0/imm32
24946     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
24947     (flush _test-output-buffered-file)
24948 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
24954     # check output
24955     (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem")
24956     # . epilogue
24957     89/<- %esp 5/r32/ebp
24958     5d/pop-to-ebp
24959     c3/return
24960 
24961 test-shift-reg-by-literal:
24962     #   var1/ecx <- shift-left 2
24963     # =>
24964     #   c1/shift 4/subop/left %ecx 2/imm8
24965     #
24966     # . prologue
24967     55/push-ebp
24968     89/<- %ebp 4/r32/esp
24969     # setup
24970     (clear-stream _test-output-stream)
24971     (clear-stream $_test-output-buffered-file->buffer)
24972 $test-shift-reg-by-literal:initialize-var-type:
24973     # var type/ecx: (payload type-tree) = int
24974     68/push 0/imm32/right:null
24975     68/push 0/imm32/right:null
24976     68/push 0/imm32/left:unused
24977     68/push 1/imm32/value:int
24978     68/push 1/imm32/is-atom?:true
24979     68/push 0x11/imm32/alloc-id:fake:payload
24980     89/<- %ecx 4/r32/esp
24981 $test-shift-reg-by-literal:initialize-var:
24982     # var v/ecx: (payload var)
24983     68/push 0/imm32/register
24984     68/push 0/imm32/register
24985     68/push 0/imm32/no-stack-offset
24986     68/push 1/imm32/block-depth
24987     51/push-ecx
24988     68/push 0x11/imm32/alloc-id:fake
24989     68/push 0/imm32/name
24990     68/push 0/imm32/name
24991     68/push 0x11/imm32/alloc-id:fake:payload
24992     89/<- %ecx 4/r32/esp
24993 $test-shift-reg-by-literal:initialize-var-name:
24994     # v->name = "v"
24995     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
24996     (copy-array Heap "v" %eax)
24997 $test-shift-reg-by-literal:initialize-var-register:
24998     # v->register = "ecx"
24999     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
25000     (copy-array Heap "ecx" %eax)
25001 $test-shift-reg-by-literal:initialize-literal-type:
25002     # var type/edx: (payload type-tree) = literal
25003     68/push 0/imm32/right:null
25004     68/push 0/imm32/right:null
25005     68/push 0/imm32/left:unused
25006     68/push 0/imm32/value:literal
25007     68/push 1/imm32/is-atom?:true
25008     68/push 0x11/imm32/alloc-id:fake:payload
25009     89/<- %edx 4/r32/esp
25010 $test-shift-reg-by-literal:initialize-literal:
25011     # var l/edx: (payload var)
25012     68/push 0/imm32/register
25013     68/push 0/imm32/register
25014     68/push 0/imm32/no-stack-offset
25015     68/push 1/imm32/block-depth
25016     52/push-edx
25017     68/push 0x11/imm32/alloc-id:fake
25018     68/push 0/imm32/name
25019     68/push 0/imm32/name
25020     68/push 0x11/imm32/alloc-id:fake:payload
25021     89/<- %edx 4/r32/esp
25022 $test-shift-reg-by-literal:initialize-literal-value:
25023     # l->name = "2"
25024     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
25025     (copy-array Heap "2" %eax)
25026 $test-shift-reg-by-literal:initialize-inouts:
25027     # var inouts/esi: (payload stmt-var) = [l]
25028     68/push 0/imm32/is-deref:false
25029     68/push 0/imm32/next
25030     68/push 0/imm32/next
25031     52/push-edx/l
25032     68/push 0x11/imm32/alloc-id:fake
25033     68/push 0x11/imm32/alloc-id:fake:payload
25034     89/<- %esi 4/r32/esp
25035 $test-shift-reg-by-literal:initialize-outputs:
25036     # var outputs/edi: (payload stmt-var) = [v]
25037     68/push 0/imm32/is-deref:false
25038     68/push 0/imm32/next
25039     68/push 0/imm32/next
25040     51/push-ecx/v
25041     68/push 0x11/imm32/alloc-id:fake
25042     68/push 0x11/imm32/alloc-id:fake:payload
25043     89/<- %edi 4/r32/esp
25044 $test-shift-reg-by-literal:initialize-stmt:
25045     # var stmt/esi: (addr statement)
25046     68/push 0/imm32/next
25047     68/push 0/imm32/next
25048     57/push-edi/outputs
25049     68/push 0x11/imm32/alloc-id:fake
25050     56/push-esi/inouts
25051     68/push 0x11/imm32/alloc-id:fake
25052     68/push 0/imm32/operation
25053     68/push 0/imm32/operation
25054     68/push 1/imm32/tag:stmt1
25055     89/<- %esi 4/r32/esp
25056 $test-shift-reg-by-literal:initialize-stmt-operation:
25057     # stmt->operation = "shift-left"
25058     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
25059     (copy-array Heap "shift-left" %eax)
25060     # convert
25061     c7 0/subop/copy *Curr-block-depth 0/imm32
25062     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
25063     (flush _test-output-buffered-file)
25064 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
25070     # check output
25071     (check-next-stream-line-equal _test-output-stream "c1/shift 4/subop/left %ecx 2/imm8" "F - test-shift-reg-by-literal")
25072     # . epilogue
25073     89/<- %esp 5/r32/ebp
25074     5d/pop-to-ebp
25075     c3/return
25076 
25077 test-shift-mem-by-literal:
25078     #   shift-left var 3
25079     # =>
25080     #   c1/shift 4/subop/left *(ebp+8) 3/imm8
25081     #
25082     # . prologue
25083     55/push-ebp
25084     89/<- %ebp 4/r32/esp
25085     # setup
25086     (clear-stream _test-output-stream)
25087     (clear-stream $_test-output-buffered-file->buffer)
25088 $test-shift-mem-by-literal:initialize-type:
25089     # var type/ecx: (payload type-tree) = int
25090     68/push 0/imm32/right:null
25091     68/push 0/imm32/right:null
25092     68/push 0/imm32/left:unused
25093     68/push 1/imm32/value:int
25094     68/push 1/imm32/is-atom?:true
25095     68/push 0x11/imm32/alloc-id:fake:payload
25096     89/<- %ecx 4/r32/esp
25097 $test-shift-mem-by-literal:initialize-var1:
25098     # var var1/ecx: (payload var)
25099     68/push 0/imm32/register
25100     68/push 0/imm32/register
25101     68/push 8/imm32/stack-offset
25102     68/push 1/imm32/block-depth
25103     51/push-ecx
25104     68/push 0x11/imm32/alloc-id:fake
25105     68/push 0/imm32/name
25106     68/push 0/imm32/name
25107     68/push 0x11/imm32/alloc-id:fake:payload
25108     89/<- %ecx 4/r32/esp
25109 $test-shift-mem-by-literal:initialize-var1-name:
25110     # var1->name = "var1"
25111     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
25112     (copy-array Heap "var1" %eax)
25113 $test-shift-mem-by-literal:initialize-literal-type:
25114     # var type/edx: (payload type-tree) = literal
25115     68/push 0/imm32/right:null
25116     68/push 0/imm32/right:null
25117     68/push 0/imm32/left:unused
25118     68/push 0/imm32/value:literal
25119     68/push 1/imm32/is-atom?:true
25120     68/push 0x11/imm32/alloc-id:fake:payload
25121     89/<- %edx 4/r32/esp
25122 $test-shift-mem-by-literal:initialize-literal:
25123     # var l/edx: (payload var)
25124     68/push 0/imm32/register
25125     68/push 0/imm32/register
25126     68/push 0/imm32/no-stack-offset
25127     68/push 1/imm32/block-depth
25128     52/push-edx
25129     68/push 0x11/imm32/alloc-id:fake
25130     68/push 0/imm32/name
25131     68/push 0/imm32/name
25132     68/push 0x11/imm32/alloc-id:fake:payload
25133     89/<- %edx 4/r32/esp
25134 $test-shift-mem-by-literal:initialize-literal-value:
25135     # l->name = "3"
25136     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
25137     (copy-array Heap "3" %eax)
25138 $test-shift-mem-by-literal:initialize-inouts:
25139     # var inouts/esi: (payload stmt-var) = [l]
25140     68/push 0/imm32/is-deref:false
25141     68/push 0/imm32/next
25142     68/push 0/imm32/next
25143     52/push-edx/l
25144     68/push 0x11/imm32/alloc-id:fake
25145     68/push 0x11/imm32/alloc-id:fake:payload
25146     89/<- %esi 4/r32/esp
25147     # var inouts = (handle stmt-var) = [var1, var2]
25148     68/push 0/imm32/is-deref:false
25149     56/push-esi/next
25150     68/push 0x11/imm32/alloc-id:fake
25151     51/push-ecx/var1
25152     68/push 0x11/imm32/alloc-id:fake
25153     68/push 0x11/imm32/alloc-id:fake:payload
25154     89/<- %esi 4/r32/esp
25155 $test-shift-mem-by-literal:initialize-stmt:
25156     # var stmt/esi: (addr statement)
25157     68/push 0/imm32/next
25158     68/push 0/imm32/next
25159     68/push 0/imm32/outputs
25160     68/push 0/imm32/outputs
25161     56/push-esi/inouts
25162     68/push 0x11/imm32/alloc-id:fake
25163     68/push 0/imm32/operation
25164     68/push 0/imm32/operation
25165     68/push 1/imm32/tag:stmt1
25166     89/<- %esi 4/r32/esp
25167 $test-shift-mem-by-literal:initialize-stmt-operation:
25168     # stmt->operation = "shift-left"
25169     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
25170     (copy-array Heap "shift-left" %eax)
25171     # convert
25172     c7 0/subop/copy *Curr-block-depth 0/imm32
25173     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
25174     (flush _test-output-buffered-file)
25175 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
25181     # check output
25182     (check-next-stream-line-equal _test-output-stream "c1/shift 4/subop/left *(ebp+0x00000008) 3/imm8" "F - test-shift-mem-by-literal")
25183     # . epilogue
25184     89/<- %esp 5/r32/ebp
25185     5d/pop-to-ebp
25186     c3/return
25187 
25188 test-compare-reg-with-reg:
25189     #   compare var1/ecx, var2/eax
25190     # =>
25191     #   39/compare %ecx 0/r32/eax
25192     #
25193     # . prologue
25194     55/push-ebp
25195     89/<- %ebp 4/r32/esp
25196     # setup
25197     (clear-stream _test-output-stream)
25198     (clear-stream $_test-output-buffered-file->buffer)
25199 $test-compare-reg-with-reg:initialize-type:
25200     # var type/ecx: (payload type-tree) = int
25201     68/push 0/imm32/right:null
25202     68/push 0/imm32/right:null
25203     68/push 0/imm32/left:unused
25204     68/push 1/imm32/value:int
25205     68/push 1/imm32/is-atom?:true
25206     68/push 0x11/imm32/alloc-id:fake:payload
25207     89/<- %ecx 4/r32/esp
25208 $test-compare-reg-with-reg:initialize-var1:
25209     # var var1/ecx: (payload var)
25210     68/push 0/imm32/register
25211     68/push 0/imm32/register
25212     68/push 0/imm32/no-stack-offset
25213     68/push 1/imm32/block-depth
25214     51/push-ecx
25215     68/push 0x11/imm32/alloc-id:fake
25216     68/push 0/imm32/name
25217     68/push 0/imm32/name
25218     68/push 0x11/imm32/alloc-id:fake:payload
25219     89/<- %ecx 4/r32/esp
25220 $test-compare-reg-with-reg:initialize-var1-name:
25221     # var1->name = "var1"
25222     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
25223     (copy-array Heap "var1" %eax)
25224 $test-compare-reg-with-reg:initialize-var1-register:
25225     # var1->register = "ecx"
25226     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
25227     (copy-array Heap "ecx" %eax)
25228 $test-compare-reg-with-reg:initialize-var2:
25229     # var var2/edx: (payload var)
25230     68/push 0/imm32/register
25231     68/push 0/imm32/register
25232     68/push 0/imm32/no-stack-offset
25233     68/push 1/imm32/block-depth
25234     ff 6/subop/push *(ecx+0x10)
25235     68/push 0x11/imm32/alloc-id:fake
25236     68/push 0/imm32/name
25237     68/push 0/imm32/name
25238     68/push 0x11/imm32/alloc-id:fake:payload
25239     89/<- %edx 4/r32/esp
25240 $test-compare-reg-with-reg:initialize-var2-name:
25241     # var2->name = "var2"
25242     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
25243     (copy-array Heap "var2" %eax)
25244 $test-compare-reg-with-reg:initialize-var2-register:
25245     # var2->register = "eax"
25246     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
25247     (copy-array Heap "eax" %eax)
25248 $test-compare-reg-with-reg:initialize-inouts:
25249     # var inouts/esi: (payload stmt-var) = [var2]
25250     68/push 0/imm32/is-deref:false
25251     68/push 0/imm32/next
25252     68/push 0/imm32/next
25253     52/push-edx/var2
25254     68/push 0x11/imm32/alloc-id:fake
25255     68/push 0x11/imm32/alloc-id:fake:payload
25256     89/<- %esi 4/r32/esp
25257     # inouts = [var1, var2]
25258     68/push 0/imm32/is-deref:false
25259     56/push-esi/next
25260     68/push 0x11/imm32/alloc-id:fake
25261     51/push-ecx/var1
25262     68/push 0x11/imm32/alloc-id:fake
25263     68/push 0x11/imm32/alloc-id:fake:payload
25264     89/<- %esi 4/r32/esp
25265 $test-compare-reg-with-reg:initialize-stmt:
25266     # var stmt/esi: (addr statement)
25267     68/push 0/imm32/next
25268     68/push 0/imm32/next
25269     68/push 0/imm32/outputs
25270     68/push 0/imm32/outputs
25271     56/push-esi/inouts
25272     68/push 0x11/imm32/alloc-id:fake
25273     68/push 0/imm32/operation
25274     68/push 0/imm32/operation
25275     68/push 1/imm32/tag:stmt1
25276     89/<- %esi 4/r32/esp
25277 $test-compare-reg-with-reg:initialize-stmt-operation:
25278     # stmt->operation = "compare"
25279     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
25280     (copy-array Heap "compare" %eax)
25281     # convert
25282     c7 0/subop/copy *Curr-block-depth 0/imm32
25283     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
25284     (flush _test-output-buffered-file)
25285 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
25291     # check output
25292     (check-next-stream-line-equal _test-output-stream "39/compare-> %ecx 0x00000000/r32" "F - test-compare-reg-with-reg")
25293     # . epilogue
25294     89/<- %esp 5/r32/ebp
25295     5d/pop-to-ebp
25296     c3/return
25297 
25298 test-compare-mem-with-reg:
25299     #   compare var1, var2/eax
25300     # =>
25301     #   39/compare *(ebp+___) 0/r32/eax
25302     #
25303     # . prologue
25304     55/push-ebp
25305     89/<- %ebp 4/r32/esp
25306     # setup
25307     (clear-stream _test-output-stream)
25308     (clear-stream $_test-output-buffered-file->buffer)
25309 $test-compare-mem-with-reg:initialize-type:
25310     # var type/ecx: (payload type-tree) = int
25311     68/push 0/imm32/right:null
25312     68/push 0/imm32/right:null
25313     68/push 0/imm32/left:unused
25314     68/push 1/imm32/value:int
25315     68/push 1/imm32/is-atom?:true
25316     68/push 0x11/imm32/alloc-id:fake:payload
25317     89/<- %ecx 4/r32/esp
25318 $test-compare-mem-with-reg:initialize-var1:
25319     # var var1/ecx: (payload var)
25320     68/push 0/imm32/register
25321     68/push 0/imm32/register
25322     68/push 8/imm32/stack-offset
25323     68/push 1/imm32/block-depth
25324     51/push-ecx
25325     68/push 0x11/imm32/alloc-id:fake
25326     68/push 0/imm32/name
25327     68/push 0/imm32/name
25328     68/push 0x11/imm32/alloc-id:fake:payload
25329     89/<- %ecx 4/r32/esp
25330 $test-compare-mem-with-reg:initialize-var1-name:
25331     # var1->name = "var1"
25332     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
25333     (copy-array Heap "var1" %eax)
25334 $test-compare-mem-with-reg:initialize-var2:
25335     # var var2/edx: (payload var)
25336     68/push 0/imm32/register
25337     68/push 0/imm32/register
25338     68/push 0/imm32/no-stack-offset
25339     68/push 1/imm32/block-depth
25340     ff 6/subop/push *(ecx+0x10)
25341     68/push 0x11/imm32/alloc-id:fake
25342     68/push 0/imm32/name
25343     68/push 0/imm32/name
25344     68/push 0x11/imm32/alloc-id:fake:payload
25345     89/<- %edx 4/r32/esp
25346 $test-compare-mem-with-reg:initialize-var2-name:
25347     # var2->name = "var2"
25348     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
25349     (copy-array Heap "var2" %eax)
25350 $test-compare-mem-with-reg:initialize-var2-register:
25351     # var2->register = "eax"
25352     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
25353     (copy-array Heap "eax" %eax)
25354 $test-compare-mem-with-reg:initialize-inouts:
25355     # var inouts/esi: (payload stmt-var) = [var2]
25356     68/push 0/imm32/is-deref:false
25357     68/push 0/imm32/next
25358     68/push 0/imm32/next
25359     52/push-edx/var2
25360     68/push 0x11/imm32/alloc-id:fake
25361     68/push 0x11/imm32/alloc-id:fake:payload
25362     89/<- %esi 4/r32/esp
25363     # inouts = [var1, var2]
25364     68/push 0/imm32/is-deref:false
25365     56/push-esi/next
25366     68/push 0x11/imm32/alloc-id:fake
25367     51/push-ecx/var1
25368     68/push 0x11/imm32/alloc-id:fake
25369     68/push 0x11/imm32/alloc-id:fake:payload
25370     89/<- %esi 4/r32/esp
25371 $test-compare-mem-with-reg:initialize-stmt:
25372     # var stmt/esi: (addr statement)
25373     68/push 0/imm32/next
25374     68/push 0/imm32/next
25375     68/push 0/imm32/outputs
25376     68/push 0/imm32/outputs
25377     56/push-esi/inouts
25378     68/push 0x11/imm32/alloc-id:fake
25379     68/push 0/imm32/operation
25380     68/push 0/imm32/operation
25381     68/push 1/imm32/tag:stmt1
25382     89/<- %esi 4/r32/esp
25383 $test-compare-mem-with-reg:initialize-stmt-operation:
25384     # stmt->operation = "compare"
25385     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
25386     (copy-array Heap "compare" %eax)
25387     # convert
25388     c7 0/subop/copy *Curr-block-depth 0/imm32
25389     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
25390     (flush _test-output-buffered-file)
25391 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
25397     # check output
25398     (check-next-stream-line-equal _test-output-stream "39/compare-> *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-mem-with-reg")
25399     # . epilogue
25400     89/<- %esp 5/r32/ebp
25401     5d/pop-to-ebp
25402     c3/return
25403 
25404 test-compare-reg-with-mem:
25405     #   compare var1/eax, var2
25406     # =>
25407     #   3b/compare<- *(ebp+___) 0/r32/eax
25408     #
25409     # . prologue
25410     55/push-ebp
25411     89/<- %ebp 4/r32/esp
25412     # setup
25413     (clear-stream _test-output-stream)
25414     (clear-stream $_test-output-buffered-file->buffer)
25415 $test-compare-reg-with-mem:initialize-type:
25416     # var type/ecx: (payload type-tree) = int
25417     68/push 0/imm32/right:null
25418     68/push 0/imm32/right:null
25419     68/push 0/imm32/left:unused
25420     68/push 1/imm32/value:int
25421     68/push 1/imm32/is-atom?:true
25422     68/push 0x11/imm32/alloc-id:fake:payload
25423     89/<- %ecx 4/r32/esp
25424 $test-compare-reg-with-mem:initialize-var1:
25425     # var var1/ecx: (payload var)
25426     68/push 0/imm32/register
25427     68/push 0/imm32/register
25428     68/push 0/imm32/no-stack-offset
25429     68/push 1/imm32/block-depth
25430     51/push-ecx
25431     68/push 0x11/imm32/alloc-id:fake
25432     68/push 0/imm32/name
25433     68/push 0/imm32/name
25434     68/push 0x11/imm32/alloc-id:fake:payload
25435     89/<- %ecx 4/r32/esp
25436 $test-compare-reg-with-mem:initialize-var1-name:
25437     # var1->name = "var1"
25438     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
25439     (copy-array Heap "var1" %eax)
25440 $test-compare-reg-with-mem:initialize-var1-register:
25441     # var1->register = "eax"
25442     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
25443     (copy-array Heap "eax" %eax)
25444 $test-compare-reg-with-mem:initialize-var2:
25445     # var var2/edx: (payload var)
25446     68/push 0/imm32/register
25447     68/push 0/imm32/register
25448     68/push 8/imm32/stack-offset
25449     68/push 1/imm32/block-depth
25450     ff 6/subop/push *(ecx+0x10)
25451     68/push 0x11/imm32/alloc-id:fake
25452     68/push 0/imm32/name
25453     68/push 0/imm32/name
25454     68/push 0x11/imm32/alloc-id:fake:payload
25455     89/<- %edx 4/r32/esp
25456 $test-compare-reg-with-mem:initialize-var2-name:
25457     # var2->name = "var2"
25458     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
25459     (copy-array Heap "var2" %eax)
25460 $test-compare-reg-with-mem:initialize-inouts:
25461     # var inouts/esi: (payload stmt-var) = [var2]
25462     68/push 0/imm32/is-deref:false
25463     68/push 0/imm32/next
25464     68/push 0/imm32/next
25465     52/push-edx/var2
25466     68/push 0x11/imm32/alloc-id:fake
25467     68/push 0x11/imm32/alloc-id:fake:payload
25468     89/<- %esi 4/r32/esp
25469     # inouts = [var1, var2]
25470     68/push 0/imm32/is-deref:false
25471     56/push-esi/next
25472     68/push 0x11/imm32/alloc-id:fake
25473     51/push-ecx/var1
25474     68/push 0x11/imm32/alloc-id:fake
25475     68/push 0x11/imm32/alloc-id:fake:payload
25476     89/<- %esi 4/r32/esp
25477 $test-compare-reg-with-mem:initialize-stmt:
25478     # var stmt/esi: (addr statement)
25479     68/push 0/imm32/next
25480     68/push 0/imm32/next
25481     68/push 0/imm32/outputs
25482     68/push 0/imm32/outputs
25483     56/push-esi/inouts
25484     68/push 0x11/imm32/alloc-id:fake
25485     68/push 0/imm32/operation
25486     68/push 0/imm32/operation
25487     68/push 1/imm32/tag:stmt1
25488     89/<- %esi 4/r32/esp
25489 $test-compare-reg-with-mem:initialize-stmt-operation:
25490     # stmt->operation = "compare"
25491     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
25492     (copy-array Heap "compare" %eax)
25493     # convert
25494     c7 0/subop/copy *Curr-block-depth 0/imm32
25495     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
25496     (flush _test-output-buffered-file)
25497 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
25503     # check output
25504     (check-next-stream-line-equal _test-output-stream "3b/compare<- *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-reg-with-mem")
25505     # . epilogue
25506     89/<- %esp 5/r32/ebp
25507     5d/pop-to-ebp
25508     c3/return
25509 
25510 test-compare-mem-with-literal:
25511     #   compare var1, 0x34
25512     # =>
25513     #   81 7/subop/compare *(ebp+___) 0x34/imm32
25514     #
25515     # . prologue
25516     55/push-ebp
25517     89/<- %ebp 4/r32/esp
25518     # setup
25519     (clear-stream _test-output-stream)
25520     (clear-stream $_test-output-buffered-file->buffer)
25521 $test-compare-mem-with-literal:initialize-type:
25522     # var type/ecx: (payload type-tree) = int
25523     68/push 0/imm32/right:null
25524     68/push 0/imm32/right:null
25525     68/push 0/imm32/left:unused
25526     68/push 1/imm32/value:int
25527     68/push 1/imm32/is-atom?:true
25528     68/push 0x11/imm32/alloc-id:fake:payload
25529     89/<- %ecx 4/r32/esp
25530 $test-compare-mem-with-literal:initialize-var1:
25531     # var var1/ecx: (payload var)
25532     68/push 0/imm32/register
25533     68/push 0/imm32/register
25534     68/push 8/imm32/stack-offset
25535     68/push 1/imm32/block-depth
25536     51/push-ecx
25537     68/push 0x11/imm32/alloc-id:fake
25538     68/push 0/imm32/name
25539     68/push 0/imm32/name
25540     68/push 0x11/imm32/alloc-id:fake:payload
25541     89/<- %ecx 4/r32/esp
25542 $test-compare-mem-with-literal:initialize-var1-name:
25543     # var1->name = "var1"
25544     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
25545     (copy-array Heap "var1" %eax)
25546 $test-compare-mem-with-literal:initialize-literal-type:
25547     # var type/edx: (payload type-tree) = literal
25548     68/push 0/imm32/right:null
25549     68/push 0/imm32/right:null
25550     68/push 0/imm32/left:unused
25551     68/push 0/imm32/value:literal
25552     68/push 1/imm32/is-atom?:true
25553     68/push 0x11/imm32/alloc-id:fake:payload
25554     89/<- %edx 4/r32/esp
25555 $test-compare-mem-with-literal:initialize-literal:
25556     # var l/edx: (payload var)
25557     68/push 0/imm32/register
25558     68/push 0/imm32/register
25559     68/push 0/imm32/no-stack-offset
25560     68/push 1/imm32/block-depth
25561     52/push-edx
25562     68/push 0x11/imm32/alloc-id:fake
25563     68/push 0/imm32/name
25564     68/push 0/imm32/name
25565     68/push 0x11/imm32/alloc-id:fake:payload
25566     89/<- %edx 4/r32/esp
25567 $test-compare-mem-with-literal:initialize-literal-value:
25568     # l->name = "0x34"
25569     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
25570     (copy-array Heap "0x34" %eax)
25571 $test-compare-mem-with-literal:initialize-inouts:
25572     # var inouts/esi: (payload stmt-var) = [l]
25573     68/push 0/imm32/is-deref:false
25574     68/push 0/imm32/next
25575     68/push 0/imm32/next
25576     52/push-edx/l
25577     68/push 0x11/imm32/alloc-id:fake
25578     68/push 0x11/imm32/alloc-id:fake:payload
25579     89/<- %esi 4/r32/esp
25580     # var inouts = (handle stmt-var) = [var1, var2]
25581     68/push 0/imm32/is-deref:false
25582     56/push-esi/next
25583     68/push 0x11/imm32/alloc-id:fake
25584     51/push-ecx/var1
25585     68/push 0x11/imm32/alloc-id:fake
25586     68/push 0x11/imm32/alloc-id:fake:payload
25587     89/<- %esi 4/r32/esp
25588 $test-compare-mem-with-literal:initialize-stmt:
25589     # var stmt/esi: (addr statement)
25590     68/push 0/imm32/next
25591     68/push 0/imm32/next
25592     68/push 0/imm32/outputs
25593     68/push 0/imm32/outputs
25594     56/push-esi/inouts
25595     68/push 0x11/imm32/alloc-id:fake
25596     68/push 0/imm32/operation
25597     68/push 0/imm32/operation
25598     68/push 1/imm32/tag:stmt1
25599     89/<- %esi 4/r32/esp
25600 $test-compare-mem-with-literal:initialize-stmt-operation:
25601     # stmt->operation = "compare"
25602     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
25603     (copy-array Heap "compare" %eax)
25604     # convert
25605     c7 0/subop/copy *Curr-block-depth 0/imm32
25606     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
25607     (flush _test-output-buffered-file)
25608 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
25614     # check output
25615     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare *(ebp+0x00000008) 0x34/imm32" "F - test-compare-mem-with-literal")
25616     # . epilogue
25617     89/<- %esp 5/r32/ebp
25618     5d/pop-to-ebp
25619     c3/return
25620 
25621 test-compare-eax-with-literal:
25622     #   compare var1/eax 0x34
25623     # =>
25624     #   3d/compare-eax-with 0x34/imm32
25625     #
25626     # . prologue
25627     55/push-ebp
25628     89/<- %ebp 4/r32/esp
25629     # setup
25630     (clear-stream _test-output-stream)
25631     (clear-stream $_test-output-buffered-file->buffer)
25632 $test-compare-eax-with-literal:initialize-type:
25633     # var type/ecx: (payload type-tree) = int
25634     68/push 0/imm32/right:null
25635     68/push 0/imm32/right:null
25636     68/push 0/imm32/left:unused
25637     68/push 1/imm32/value:int
25638     68/push 1/imm32/is-atom?:true
25639     68/push 0x11/imm32/alloc-id:fake:payload
25640     89/<- %ecx 4/r32/esp
25641 $test-compare-eax-with-literal:initialize-var1:
25642     # var var1/ecx: (payload var)
25643     68/push 0/imm32/register
25644     68/push 0/imm32/register
25645     68/push 0/imm32/no-stack-offset
25646     68/push 1/imm32/block-depth
25647     51/push-ecx
25648     68/push 0x11/imm32/alloc-id:fake
25649     68/push 0/imm32/name
25650     68/push 0/imm32/name
25651     68/push 0x11/imm32/alloc-id:fake:payload
25652     89/<- %ecx 4/r32/esp
25653 $test-compare-eax-with-literal:initialize-var1-name:
25654     # var1->name = "var1"
25655     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
25656     (copy-array Heap "var1" %eax)
25657 $test-compare-eax-with-literal:initialize-var1-register:
25658     # v->register = "eax"
25659     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
25660     (copy-array Heap "eax" %eax)
25661 $test-compare-eax-with-literal:initialize-literal-type:
25662     # var type/edx: (payload type-tree) = literal
25663     68/push 0/imm32/right:null
25664     68/push 0/imm32/right:null
25665     68/push 0/imm32/left:unused
25666     68/push 0/imm32/value:literal
25667     68/push 1/imm32/is-atom?:true
25668     68/push 0x11/imm32/alloc-id:fake:payload
25669     89/<- %edx 4/r32/esp
25670 $test-compare-eax-with-literal:initialize-literal:
25671     # var l/edx: (payload var)
25672     68/push 0/imm32/register
25673     68/push 0/imm32/register
25674     68/push 0/imm32/no-stack-offset
25675     68/push 1/imm32/block-depth
25676     52/push-edx
25677     68/push 0x11/imm32/alloc-id:fake
25678     68/push 0/imm32/name
25679     68/push 0/imm32/name
25680     68/push 0x11/imm32/alloc-id:fake:payload
25681     89/<- %edx 4/r32/esp
25682 $test-compare-eax-with-literal:initialize-literal-value:
25683     # l->name = "0x34"
25684     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
25685     (copy-array Heap "0x34" %eax)
25686 $test-compare-eax-with-literal:initialize-inouts:
25687     # var inouts/esi: (payload stmt-var) = [l]
25688     68/push 0/imm32/is-deref:false
25689     68/push 0/imm32/next
25690     68/push 0/imm32/next
25691     52/push-edx/l
25692     68/push 0x11/imm32/alloc-id:fake
25693     68/push 0x11/imm32/alloc-id:fake:payload
25694     89/<- %esi 4/r32/esp
25695     # var inouts = (handle stmt-var) = [var1, var2]
25696     68/push 0/imm32/is-deref:false
25697     56/push-esi/next
25698     68/push 0x11/imm32/alloc-id:fake
25699     51/push-ecx/var1
25700     68/push 0x11/imm32/alloc-id:fake
25701     68/push 0x11/imm32/alloc-id:fake:payload
25702     89/<- %esi 4/r32/esp
25703 $test-compare-eax-with-literal:initialize-stmt:
25704     # var stmt/esi: (addr statement)
25705     68/push 0/imm32/next
25706     68/push 0/imm32/next
25707     68/push 0/imm32/outputs
25708     68/push 0/imm32/outputs
25709     56/push-esi/inouts
25710     68/push 0x11/imm32/alloc-id:fake
25711     68/push 0/imm32/operation
25712     68/push 0/imm32/operation
25713     68/push 1/imm32/tag:stmt1
25714     89/<- %esi 4/r32/esp
25715 $test-compare-eax-with-literal:initialize-stmt-operation:
25716     # stmt->operation = "compare"
25717     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
25718     (copy-array Heap "compare" %eax)
25719     # convert
25720     c7 0/subop/copy *Curr-block-depth 0/imm32
25721     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
25722     (flush _test-output-buffered-file)
25723 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
25729     # check output
25730     (check-next-stream-line-equal _test-output-stream "3d/compare-eax-with 0x34/imm32" "F - test-compare-eax-with-literal")
25731     # . epilogue
25732     89/<- %esp 5/r32/ebp
25733     5d/pop-to-ebp
25734     c3/return
25735 
25736 test-compare-reg-with-literal:
25737     #   compare var1/ecx 0x34
25738     # =>
25739     #   81 7/subop/compare %ecx 0x34/imm32
25740     #
25741     # . prologue
25742     55/push-ebp
25743     89/<- %ebp 4/r32/esp
25744     # setup
25745     (clear-stream _test-output-stream)
25746     (clear-stream $_test-output-buffered-file->buffer)
25747 $test-compare-reg-with-literal:initialize-type:
25748     # var type/ecx: (payload type-tree) = int
25749     68/push 0/imm32/right:null
25750     68/push 0/imm32/right:null
25751     68/push 0/imm32/left:unused
25752     68/push 1/imm32/value:int
25753     68/push 1/imm32/is-atom?:true
25754     68/push 0x11/imm32/alloc-id:fake:payload
25755     89/<- %ecx 4/r32/esp
25756 $test-compare-reg-with-literal:initialize-var1:
25757     # var var1/ecx: (payload var)
25758     68/push 0/imm32/register
25759     68/push 0/imm32/register
25760     68/push 0/imm32/no-stack-offset
25761     68/push 1/imm32/block-depth
25762     51/push-ecx
25763     68/push 0x11/imm32/alloc-id:fake
25764     68/push 0/imm32/name
25765     68/push 0/imm32/name
25766     68/push 0x11/imm32/alloc-id:fake:payload
25767     89/<- %ecx 4/r32/esp
25768 $test-compare-reg-with-literal:initialize-var1-name:
25769     # var1->name = "var1"
25770     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
25771     (copy-array Heap "var1" %eax)
25772 $test-compare-reg-with-literal:initialize-var1-register:
25773     # v->register = "ecx"
25774     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
25775     (copy-array Heap "ecx" %eax)
25776 $test-compare-reg-with-literal:initialize-literal-type:
25777     # var type/edx: (payload type-tree) = literal
25778     68/push 0/imm32/right:null
25779     68/push 0/imm32/right:null
25780     68/push 0/imm32/left:unused
25781     68/push 0/imm32/value:literal
25782     68/push 1/imm32/is-atom?:true
25783     68/push 0x11/imm32/alloc-id:fake:payload
25784     89/<- %edx 4/r32/esp
25785 $test-compare-reg-with-literal:initialize-literal:
25786     # var l/edx: (payload var)
25787     68/push 0/imm32/register
25788     68/push 0/imm32/register
25789     68/push 0/imm32/no-stack-offset
25790     68/push 1/imm32/block-depth
25791     52/push-edx
25792     68/push 0x11/imm32/alloc-id:fake
25793     68/push 0/imm32/name
25794     68/push 0/imm32/name
25795     68/push 0x11/imm32/alloc-id:fake:payload
25796     89/<- %edx 4/r32/esp
25797 $test-compare-reg-with-literal:initialize-literal-value:
25798     # l->name = "0x34"
25799     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
25800     (copy-array Heap "0x34" %eax)
25801 $test-compare-reg-with-literal:initialize-inouts:
25802     # var inouts/esi: (payload stmt-var) = [l]
25803     68/push 0/imm32/is-deref:false
25804     68/push 0/imm32/next
25805     68/push 0/imm32/next
25806     52/push-edx/l
25807     68/push 0x11/imm32/alloc-id:fake
25808     68/push 0x11/imm32/alloc-id:fake:payload
25809     89/<- %esi 4/r32/esp
25810     # var inouts = (handle stmt-var) = [var1, var2]
25811     68/push 0/imm32/is-deref:false
25812     56/push-esi/next
25813     68/push 0x11/imm32/alloc-id:fake
25814     51/push-ecx/var1
25815     68/push 0x11/imm32/alloc-id:fake
25816     68/push 0x11/imm32/alloc-id:fake:payload
25817     89/<- %esi 4/r32/esp
25818 $test-compare-reg-with-literal:initialize-stmt:
25819     # var stmt/esi: (addr statement)
25820     68/push 0/imm32/next
25821     68/push 0/imm32/next
25822     68/push 0/imm32/outputs
25823     68/push 0/imm32/outputs
25824     56/push-esi/inouts
25825     68/push 0x11/imm32/alloc-id:fake
25826     68/push 0/imm32/operation
25827     68/push 0/imm32/operation
25828     68/push 1/imm32/tag:stmt1
25829     89/<- %esi 4/r32/esp
25830 $test-compare-reg-with-literal:initialize-stmt-operation:
25831     # stmt->operation = "compare"
25832     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
25833     (copy-array Heap "compare" %eax)
25834     # convert
25835     c7 0/subop/copy *Curr-block-depth 0/imm32
25836     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
25837     (flush _test-output-buffered-file)
25838 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
25844     # check output
25845     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare %ecx 0x34/imm32" "F - test-compare-reg-with-literal")
25846     # . epilogue
25847     89/<- %esp 5/r32/ebp
25848     5d/pop-to-ebp
25849     c3/return
25850 
25851 test-emit-subx-stmt-function-call:
25852     # Call a function on a variable on the stack.
25853     #   f foo
25854     # =>
25855     #   (f *(ebp-8))
25856     # (Changing the function name supports overloading in general, but here it
25857     # just serves to help disambiguate things.)
25858     #
25859     # There's a variable on the var stack as follows:
25860     #   name: 'foo'
25861     #   type: int
25862     #   stack-offset: -8
25863     #
25864     # There's nothing in primitives.
25865     #
25866     # We don't perform any checking here on the type of 'f'.
25867     #
25868     # . prologue
25869     55/push-ebp
25870     89/<- %ebp 4/r32/esp
25871     # setup
25872     (clear-stream _test-output-stream)
25873     (clear-stream $_test-output-buffered-file->buffer)
25874 $test-emit-subx-function-call:initialize-type:
25875     # var type/ecx: (payload type-tree) = int
25876     68/push 0/imm32/right:null
25877     68/push 0/imm32/right:null
25878     68/push 0/imm32/left:unused
25879     68/push 1/imm32/value:int
25880     68/push 1/imm32/is-atom?:true
25881     68/push 0x11/imm32/alloc-id:fake:payload
25882     89/<- %ecx 4/r32/esp
25883 $test-emit-subx-function-call:initialize-var:
25884     # var var-foo/ecx: (payload var) = var(type)
25885     68/push 0/imm32/no-register
25886     68/push 0/imm32/no-register
25887     68/push -8/imm32/stack-offset
25888     68/push 1/imm32/block-depth
25889     51/push-ecx/type
25890     68/push 0x11/imm32/alloc-id:fake
25891     68/push 0/imm32/name
25892     68/push 0/imm32/name
25893     68/push 0x11/imm32/alloc-id:fake:payload
25894     89/<- %ecx 4/r32/esp
25895 $test-emit-subx-function-call:initialize-var-name:
25896     # var-foo->name = "foo"
25897     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
25898     (copy-array Heap "foo" %eax)
25899 $test-emit-subx-function-call:initialize-stmt-var:
25900     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
25901     68/push 0/imm32/is-deref:false
25902     68/push 0/imm32/next
25903     68/push 0/imm32/next
25904     51/push-ecx/var-foo
25905     68/push 0x11/imm32/alloc-id:fake
25906     68/push 0x11/imm32/alloc-id:fake:payload
25907     89/<- %ebx 4/r32/esp
25908 $test-emit-subx-function-call:initialize-stmt:
25909     # var stmt/esi: (addr statement)
25910     68/push 0/imm32/no-outputs
25911     68/push 0/imm32/no-outputs
25912     53/push-ebx/inouts
25913     68/push 0x11/imm32/alloc-id:fake
25914     68/push 0/imm32/operation
25915     68/push 0/imm32/operation
25916     68/push 1/imm32/tag
25917     89/<- %esi 4/r32/esp
25918 $test-emit-subx-function-call:initialize-stmt-operation:
25919     # stmt->operation = "f"
25920     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
25921     (copy-array Heap "f" %eax)
25922     # convert
25923     c7 0/subop/copy *Curr-block-depth 0/imm32
25924     (emit-subx-stmt _test-output-buffered-file %esi 0 Stderr 0)
25925     (flush _test-output-buffered-file)
25926 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
25932     # check output
25933     (check-next-stream-line-equal _test-output-stream "(f *(ebp+0xfffffff8))" "F - test-emit-subx-stmt-function-call")
25934     # . epilogue
25935     89/<- %esp 5/r32/ebp
25936     5d/pop-to-ebp
25937     c3/return
25938 
25939 test-emit-subx-stmt-function-call-with-literal-arg:
25940     # Call a function on a literal.
25941     #   f 0x34
25942     # =>
25943     #   (f2 0x34)
25944     #
25945     # . prologue
25946     55/push-ebp
25947     89/<- %ebp 4/r32/esp
25948     # setup
25949     (clear-stream _test-output-stream)
25950     (clear-stream $_test-output-buffered-file->buffer)
25951 $test-emit-subx-function-call-with-literal-arg:initialize-type:
25952     # var type/ecx: (payload type-tree) = int
25953     68/push 0/imm32/right:null
25954     68/push 0/imm32/right:null
25955     68/push 0/imm32/left:unused
25956     68/push 0/imm32/value:literal
25957     68/push 1/imm32/is-atom?:true
25958     68/push 0x11/imm32/alloc-id:fake:payload
25959     89/<- %ecx 4/r32/esp
25960 $test-emit-subx-function-call-with-literal-arg:initialize-var:
25961     # var var-foo/ecx: (payload var) = var(lit)
25962     68/push 0/imm32/no-register
25963     68/push 0/imm32/no-register
25964     68/push 0/imm32/no-stack-offset
25965     68/push 1/imm32/block-depth
25966     51/push-ecx/type
25967     68/push 0x11/imm32/alloc-id:fake
25968     68/push 0/imm32/name
25969     68/push 0/imm32/name
25970     68/push 0x11/imm32/alloc-id:fake:payload
25971     89/<- %ecx 4/r32/esp
25972 $test-emit-subx-function-call-with-literal-arg:initialize-var-name:
25973     # var-foo->name = "0x34"
25974     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
25975     (copy-array Heap "0x34" %eax)
25976 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-var:
25977     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
25978     68/push 0/imm32/is-deref:false
25979     68/push 0/imm32/next
25980     68/push 0/imm32/next
25981     51/push-ecx/var-foo
25982     68/push 0x11/imm32/alloc-id:fake
25983     68/push 0x11/imm32/alloc-id:fake:payload
25984     89/<- %ebx 4/r32/esp
25985 $test-emit-subx-function-call-with-literal-arg:initialize-stmt:
25986     # var stmt/esi: (addr statement)
25987     68/push 0/imm32/no-outputs
25988     68/push 0/imm32/no-outputs
25989     53/push-ebx/inouts
25990     68/push 0x11/imm32/alloc-id:fake
25991     68/push 0/imm32/operation
25992     68/push 0/imm32/operation
25993     68/push 1/imm32/tag
25994     89/<- %esi 4/r32/esp
25995 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-operation:
25996     # stmt->operation = "f"
25997     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
25998     (copy-array Heap "f" %eax)
25999     # convert
26000     c7 0/subop/copy *Curr-block-depth 0/imm32
26001     (emit-subx-stmt _test-output-buffered-file %esi 0 %ebx Stderr 0)
26002     (flush _test-output-buffered-file)
26003 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
26009     # check output
26010     (check-next-stream-line-equal _test-output-stream "(f 0x34)" "F - test-emit-subx-stmt-function-call-with-literal-arg")
26011     # . epilogue
26012     89/<- %esp 5/r32/ebp
26013     5d/pop-to-ebp
26014     c3/return
26015 
26016 emit-indent:  # out: (addr buffered-file), n: int
26017     # . prologue
26018     55/push-ebp
26019     89/<- %ebp 4/r32/esp
26020     # . save registers
26021     50/push-eax
26022     # var i/eax: int = n
26023     8b/-> *(ebp+0xc) 0/r32/eax
26024     {
26025       # if (i <= 0) break
26026       3d/compare-eax-with 0/imm32
26027       7e/jump-if-<= break/disp8
26028       (write-buffered *(ebp+8) "  ")
26029       48/decrement-eax
26030       eb/jump loop/disp8
26031     }
26032 $emit-indent:end:
26033     # . restore registers
26034     58/pop-to-eax
26035     # . epilogue
26036     89/<- %esp 5/r32/ebp
26037     5d/pop-to-ebp
26038     c3/return
26039 
26040 emit-subx-prologue:  # out: (addr buffered-file)
26041     # . prologue
26042     55/push-ebp
26043     89/<- %ebp 4/r32/esp
26044     #
26045     (write-buffered *(ebp+8) "  # . prologue\n")
26046     (write-buffered *(ebp+8) "  55/push-ebp\n")
26047     (write-buffered *(ebp+8) "  89/<- %ebp 4/r32/esp\n")
26048 $emit-subx-prologue:end:
26049     # . epilogue
26050     89/<- %esp 5/r32/ebp
26051     5d/pop-to-ebp
26052     c3/return
26053 
26054 emit-subx-epilogue:  # out: (addr buffered-file)
26055     # . prologue
26056     55/push-ebp
26057     89/<- %ebp 4/r32/esp
26058     #
26059     (write-buffered *(ebp+8) "  # . epilogue\n")
26060     (write-buffered *(ebp+8) "  89/<- %esp 5/r32/ebp\n")
26061     (write-buffered *(ebp+8) "  5d/pop-to-ebp\n")
26062     (write-buffered *(ebp+8) "  c3/return\n")
26063 $emit-subx-epilogue:end:
26064     # . epilogue
26065     89/<- %esp 5/r32/ebp
26066     5d/pop-to-ebp
26067     c3/return